Search code examples
pythonrequestethereummetamaskpyscript

How to send "eth_requestAccounts" to Metamask in PyScript?


I am trying to get address from installed MetaMask on the browser. We used to do this in JS as follow:

  const T1 = async () => {
    let Address = await window.ethereum.request({
      method: "eth_requestAccounts",
    });
    accountChangeHandler(Address.toString());

    //   console.log(Address.toString());
  };

or

let balance = await window.ethereum.request({
        method: "eth_getBalance",
        params: [address, "latest"],
      });

In PyScript, I know we could import js module and use window.ethereum but I am not sure how to send requests with methods. I am aware of pyfetch.

I am failing to see how I could import address or send transactions same as we use to do in JS.

I wrote this PyScript code:

from js import document, alert, window, console
from pyodide import create_proxy
from pyodide.http import pyfetch
import asyncio


document.getElementById("status").innerHTML = "Click the button to check Metamask"


async def Check_if_Metamask(param):
    if not window.ethereum:
        alert("install metamask")
    else:
        document.getElementById("status").innerHTML = "Metamask is already installed"
        document.getElementById("msg").innerHTML = "Welcome!"
        # console.log(window.ethereum.request)
        a = await window.ethereum.request(
            {
                method: "eth_requestAccounts",
            }
        )
        Address = await pyfetch(a, method="Get")
        output = Address
        console.log(output)
        console.log("This is a")
        console.log(a)


def setup():
    # Create a JsProxy for the callback function
    click_proxy = create_proxy(Check_if_Metamask)
    # Set the listener to the callback
    e = document.getElementById("submit-button2")
    e.addEventListener("click", click_proxy)


setup()

and the associated HTML is as follow

<html>
  <head>
    <title>Button Event Proxy</title>
    <!-- <link rel="stylesheet" href="../Illustration 2/pyscript.css" /> -->
    <link rel="stylesheet" href="./buttoncss.css" />
    <script defer src="../Illustration 2/pyscript.js"></script>
  </head>

  <body>
    <div id="status">Check Metamask!</div>
    <br />
    <div id="msg"></div>
    <br />
    <button class="button-17" id="submit-button2">check</button>

    <py-script src="./code.py"> </py-script>
  </body>
</html>

Solution

  • When calling javascript functions on DOM from pyscript we have to create a proxy and set it as our callback.

    <!DOCTYPE html>
     <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
        <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
      </head>
      <body>
        <button id="connect" style="color:blue" >Connect</button> 
        <py-script>
          from js import alert, window,console,document
          # since sending request to metamask async we need this
          import asyncio
          from pyodide import create_proxy
          if not window.ethereum: 
            alert("install metamask")
          if window.ethereum:
            button = document.querySelector("button")
            # you need to pass "event" arg even though you do not use it. Otherwise it will throw this error
            # TypeError: request_eth() takes 0 positional arguments but 1 was given
            async def request_eth(event):   
              try:
                await window.ethereum.request(method="eth_requestAccounts")
              except Exception as e:
                console.log(e)
            function=create_proxy(request_eth)
            button.addEventListener("click", function,False)   
        </py-script>
      </body>
    </html>