From 3b267290ce4c061968f619953232718c2f1ab145 Mon Sep 17 00:00:00 2001 From: Daniel Schiavini Date: Mon, 5 Feb 2024 16:25:05 +0100 Subject: [PATCH 1/2] Sign typed data using BrowserSigner Closes #128 --- boa/integrations/jupyter/browser.py | 18 ++++++++++++++++++ boa/integrations/jupyter/jupyter.js | 16 ++++++++-------- tests/unitary/jupyter/test_browser.py | 14 ++++++++++++-- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/boa/integrations/jupyter/browser.py b/boa/integrations/jupyter/browser.py index 7c932bca..72809807 100644 --- a/boa/integrations/jupyter/browser.py +++ b/boa/integrations/jupyter/browser.py @@ -66,6 +66,24 @@ def send_transaction(self, tx_data: dict) -> dict: ) return convert_frontend_dict(sign_data) + def sign_typed_data( + self, domain: dict[str, Any], types: dict[str, list], value: dict[str, Any] + ) -> str: + """ + Sign typed data value with types data structure for domain using the EIP-712 specification. + :param domain: The domain data structure. + :param types: The types data structure. + :param value: The value to sign. + :return: The signature. + """ + return _javascript_call( + "signTypedData", + domain, + types, + value, + timeout_message=TRANSACTION_TIMEOUT_MESSAGE, + ) + class BrowserRPC(RPC): """ diff --git a/boa/integrations/jupyter/jupyter.js b/boa/integrations/jupyter/jupyter.js index 1c262099..68f36d9e 100644 --- a/boa/integrations/jupyter/jupyter.js +++ b/boa/integrations/jupyter/jupyter.js @@ -40,17 +40,16 @@ return response.text(); } + const getSigner = () => getEthersProvider().getSigner(); + /** Load the signer via ethers user */ - const loadSigner = async () => { - const signer = await getEthersProvider().getSigner(); - return signer.getAddress(); - }; + const loadSigner = () => getSigner().then(s => s.getAddress()); /** Sign a transaction via ethers */ - async function signTransaction(transaction) { - const signer = await getEthersProvider().getSigner(); - return signer.sendTransaction(transaction); - } + const signTransaction = transaction => getSigner().then(s => s.signTransaction(transaction)); + + /** Sign a typed data via ethers */ + const signTypedData = (domain, types, value) => getSigner().then(s => s.signTypedData(domain, types, value)); /** Call an RPC method via ethers */ const rpc = (method, params) => getEthersProvider().send(method, params); @@ -91,6 +90,7 @@ window._titanoboa = { loadSigner: handleCallback(loadSigner), signTransaction: handleCallback(signTransaction), + signTypedData: handleCallback(signTypedData), waitForTransactionReceipt: handleCallback(waitForTransactionReceipt), rpc: handleCallback(rpc), multiRpc: handleCallback(multiRpc), diff --git a/tests/unitary/jupyter/test_browser.py b/tests/unitary/jupyter/test_browser.py index dc0783c4..5e58576f 100644 --- a/tests/unitary/jupyter/test_browser.py +++ b/tests/unitary/jupyter/test_browser.py @@ -6,7 +6,6 @@ from unittest.mock import MagicMock, patch import pytest -from eth_account import Account import boa @@ -124,6 +123,7 @@ def mock_fork(mock_callback): @pytest.fixture() def browser(nest_asyncio_mock, jupyter_module_mock): + # Import the browser module after the mocks have been set up from boa.integrations.jupyter import browser return browser @@ -131,7 +131,7 @@ def browser(nest_asyncio_mock, jupyter_module_mock): @pytest.fixture() def account(): - return Account.create() + return boa.env.generate_address() @pytest.fixture() @@ -152,6 +152,16 @@ def test_browser_signer_given_address(browser, display_mock, mock_inject_javascr mock_inject_javascript.assert_not_called() +def test_browser_sign_typed_data( + browser, display_mock, mock_inject_javascript, mock_callback +): + signer = browser.BrowserSigner(boa.env.generate_address()) + signature = boa.env.generate_address() + mock_callback("signTypedData", signature) + data = signer.sign_typed_data({"name": "My App"}, {"types": []}, {"data": "0x1234"}) + assert data == signature + + def test_browser_signer_no_address( mocked_token, browser, display_mock, mock_callback, mock_inject_javascript ): From b144d4c47b9f226795f03011c7e895ba589a2a2a Mon Sep 17 00:00:00 2001 From: Daniel Schiavini Date: Mon, 5 Feb 2024 16:44:15 +0100 Subject: [PATCH 2/2] Unintended change --- tests/unitary/jupyter/test_browser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unitary/jupyter/test_browser.py b/tests/unitary/jupyter/test_browser.py index 5e58576f..b5ae696e 100644 --- a/tests/unitary/jupyter/test_browser.py +++ b/tests/unitary/jupyter/test_browser.py @@ -6,6 +6,7 @@ from unittest.mock import MagicMock, patch import pytest +from eth_account import Account import boa @@ -131,7 +132,7 @@ def browser(nest_asyncio_mock, jupyter_module_mock): @pytest.fixture() def account(): - return boa.env.generate_address() + return Account.create() @pytest.fixture()