From 0339465d283b6cfb226fdac4d84306bd0801f7e4 Mon Sep 17 00:00:00 2001 From: Aaron Quirk Date: Mon, 4 Nov 2024 14:01:45 -0500 Subject: [PATCH 1/7] add ERC-20 and RPC support required for successful Uniswap transactions --- package.json | 4 +- src/lib/wallet/evm/provider.ts | 16 ++++ src/lib/wallet/evm/token.test.ts | 21 ----- src/lib/wallet/evm/token.ts | 27 ------- src/pages/Wallet/Connect.tsx | 2 +- src/scripts/liteWalletProvider/main.ts | 108 ++++++++++++++++++++++--- src/types/wallet/provider.ts | 3 + yarn.lock | 21 ++--- 8 files changed, 131 insertions(+), 71 deletions(-) create mode 100644 src/lib/wallet/evm/provider.ts delete mode 100644 src/lib/wallet/evm/token.test.ts delete mode 100644 src/lib/wallet/evm/token.ts diff --git a/package.json b/package.json index d231f3e..7fe0dac 100644 --- a/package.json +++ b/package.json @@ -47,8 +47,8 @@ "@metamask/providers": "^17.1.2", "@types/react": "^17.0.0", "@types/react-dom": "^17.0.0", - "@unstoppabledomains/config": "0.0.13", - "@unstoppabledomains/ui-components": "0.0.51-browser-extension.6", + "@unstoppabledomains/config": "0.0.16", + "@unstoppabledomains/ui-components": "0.0.51-browser-extension.8", "@unstoppabledomains/ui-kit": "0.3.24", "abitype": "^1.0.6", "async-mutex": "^0.5.0", diff --git a/src/lib/wallet/evm/provider.ts b/src/lib/wallet/evm/provider.ts new file mode 100644 index 0000000..f8206df --- /dev/null +++ b/src/lib/wallet/evm/provider.ts @@ -0,0 +1,16 @@ +import {Web3} from "web3"; + +import config from "@unstoppabledomains/config"; +import {getProviderUrl} from "@unstoppabledomains/ui-components/lib/wallet/evm/provider"; + +export const getWeb3Provider = (chainId: number) => { + const chainSymbol = Object.keys(config.BLOCKCHAINS).find(k => { + return config.BLOCKCHAINS[k].CHAIN_ID === chainId; + }); + if (!chainSymbol) { + throw new Error(`Configuration not found for chainId: ${chainId}`); + } + + const providerUrl = getProviderUrl(chainSymbol); + return new Web3(providerUrl); +}; diff --git a/src/lib/wallet/evm/token.test.ts b/src/lib/wallet/evm/token.test.ts deleted file mode 100644 index 0a4ace7..0000000 --- a/src/lib/wallet/evm/token.test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {createErc20TransferTx} from "./token"; - -describe("token transactions", () => { - it("should create an erc20 transfer tx", () => { - const tx = createErc20TransferTx( - 80002, - "0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582", - "0xCD0DAdAb45bAF9a06ce1279D1342EcC3F44845af", - "0x8ee1E1d88EBE2B44eAD162777DE787Ef6A2dC2F2", - 1, - ); - expect(tx).toMatchObject({ - chainId: 80002, - to: "0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582", - // expected data generated directly from Polygon scan using MetaMask: - // https://amoy.polygonscan.com/token/0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582?a=0x8ee1e1d88ebe2b44ead162777de787ef6a2dc2f2#writeProxyContract - data: "0xa9059cbb0000000000000000000000008ee1e1d88ebe2b44ead162777de787ef6a2dc2f20000000000000000000000000000000000000000000000000000000000000001", - value: "0", - }); - }); -}); diff --git a/src/lib/wallet/evm/token.ts b/src/lib/wallet/evm/token.ts deleted file mode 100644 index eeb8de0..0000000 --- a/src/lib/wallet/evm/token.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {erc20Abi} from "abitype/abis"; -import {Web3} from "web3"; - -import {CreateTransaction} from "@unstoppabledomains/ui-components"; - -const web3 = new Web3(); - -export const createErc20TransferTx = ( - chainId: number, - tokenAddress: string, - fromAddress: string, - toAddress: string, - amount: number, -): CreateTransaction => { - // ERC-20 contract instance for sending a specific token - const erc20Contract = new web3.eth.Contract(erc20Abi, tokenAddress, { - from: fromAddress, - }); - - // create the transaction that should be signed to execute ERC-20 transfer - return { - chainId, - to: tokenAddress, - data: erc20Contract.methods.transfer(toAddress, amount).encodeABI(), - value: "0", - }; -}; diff --git a/src/pages/Wallet/Connect.tsx b/src/pages/Wallet/Connect.tsx index efddac6..380b7c8 100644 --- a/src/pages/Wallet/Connect.tsx +++ b/src/pages/Wallet/Connect.tsx @@ -76,7 +76,7 @@ const Connect: React.FC = () => { useEffect(() => { // wait for required fields to be loaded - if (!isMounted() || !preferences || !connections) { + if (!isMounted() || !preferences || !connections || isLoaded) { return; } diff --git a/src/scripts/liteWalletProvider/main.ts b/src/scripts/liteWalletProvider/main.ts index c565c64..de0479f 100644 --- a/src/scripts/liteWalletProvider/main.ts +++ b/src/scripts/liteWalletProvider/main.ts @@ -16,6 +16,7 @@ import {Logger} from "../../lib/logger"; import {isEthAddress} from "../../lib/sherlock/matcher"; import {ResolutionData} from "../../lib/sherlock/types"; import {announceProvider} from "../../lib/wallet/evm/eip6963"; +import {getWeb3Provider} from "../../lib/wallet/evm/provider"; import {EIP_712_KEY, TypedMessage} from "../../types/wallet/eip712"; import {WalletPreferences} from "../../types/wallet/preferences"; import { @@ -172,14 +173,25 @@ class LiteWalletProvider extends EventEmitter { result = await this.handleTypedSign(clone(request.params)); break; // Transaction methods - case "eth_sendTransaction": - result = await this.handleSendTransaction(clone(request.params)); - break; case "eth_blockNumber": + result = await this.handleGetBlockNumber(); + break; + case "eth_call": + result = await this.handleReadOnlyCall(clone(request.params)); + break; + case "eth_estimateGas": + result = await this.handleEstimateGas(clone(request.params)); + break; case "eth_getTransactionByHash": - // not implemented, but stubbed out with "not found" to prevent runtime - // errors on apps that call this method - result = null; + result = await this.handleGetTransactionByHash(clone(request.params)); + break; + case "eth_getTransactionReceipt": + result = await this.handleGetTransactionReceipt( + clone(request.params), + ); + break; + case "eth_sendTransaction": + result = await this.handleSendTransaction(clone(request.params)); break; default: throw new EthereumProviderError( @@ -189,10 +201,15 @@ class LiteWalletProvider extends EventEmitter { } // result is successful - Logger.log( - "Request successful", - JSON.stringify({method: request.method, result}), - ); + try { + Logger.log( + "Request successful", + JSON.stringify({method: request.method, result}), + ); + } catch (e2: any) { + Logger.log("Request successful", request.method); + } + return result; } catch (e: any) { // result is failure @@ -499,6 +516,77 @@ class LiteWalletProvider extends EventEmitter { return [address]; } + private async handleGetBlockNumber() { + // retrieve the web3 provider for connected chain + const chainIdHex = await this.handleGetConnectedChainIds(); + const web3 = getWeb3Provider(web3utils.hexToNumber(chainIdHex) as number); + + // query the block number + const block = await web3.eth.getBlockNumber(); + return web3utils.numberToHex(block); + } + + private async handleEstimateGas(params: any[]) { + // retrieve the web3 provider for connected chain + const chainIdHex = await this.handleGetConnectedChainIds(); + const web3 = getWeb3Provider(web3utils.hexToNumber(chainIdHex) as number); + + // validate any Tx parameters have been passed + if (!params || params.length === 0) { + throw new EthereumProviderError(PROVIDER_CODE_USER_ERROR, InvalidTxError); + } + + // query the estimated gas + return web3utils.numberToHex(await web3.eth.estimateGas(params[0])); + } + + private async handleGetTransactionByHash(params: any[]) { + // retrieve the web3 provider for connected chain + const chainIdHex = await this.handleGetConnectedChainIds(); + const web3 = getWeb3Provider(web3utils.hexToNumber(chainIdHex) as number); + + // validate any Tx parameters have been passed + if (!params || params.length === 0) { + throw new EthereumProviderError(PROVIDER_CODE_USER_ERROR, InvalidTxError); + } + + // query the requested transaction + return await web3.eth.getTransaction(params[0]); + } + + private async handleGetTransactionReceipt(params: any[]) { + // retrieve the web3 provider for connected chain + const chainIdHex = await this.handleGetConnectedChainIds(); + const web3 = getWeb3Provider(web3utils.hexToNumber(chainIdHex) as number); + + // validate any Tx parameters have been passed + if (!params || params.length === 0) { + throw new EthereumProviderError(PROVIDER_CODE_USER_ERROR, InvalidTxError); + } + + // query the requested transaction + return await web3.eth.getTransactionReceipt(params[0]); + } + + private async handleReadOnlyCall(params: any[]) { + // retrieve the web3 provider for connected chain + const chainIdHex = await this.handleGetConnectedChainIds(); + const web3 = getWeb3Provider(web3utils.hexToNumber(chainIdHex) as number); + + // validate any Tx parameters have been passed + if (!params || params.length === 0) { + throw new EthereumProviderError(PROVIDER_CODE_USER_ERROR, InvalidTxError); + } + + // query the requested transaction + return await web3.eth.call( + // call parameters + params[0], + // optional block number + params.length > 1 ? params[1] : undefined, + ); + } + private async handleGetConnectedChainIds() { if (this.networkVersion) { // return hex formatted network version diff --git a/src/types/wallet/provider.ts b/src/types/wallet/provider.ts index 123390a..5aad0f6 100644 --- a/src/types/wallet/provider.ts +++ b/src/types/wallet/provider.ts @@ -8,6 +8,9 @@ export type ProviderMethod = | "eth_sendTransaction" | "eth_signTypedData_v4" | "eth_blockNumber" + | "eth_getTransactionReceipt" + | "eth_call" + | "eth_estimateGas" | "eth_getTransactionByHash" | "personal_sign" | "wallet_requestPermissions" diff --git a/yarn.lock b/yarn.lock index 1267e7c..8523465 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6271,9 +6271,9 @@ __metadata: languageName: node linkType: hard -"@unstoppabledomains/config@npm:0.0.13, @unstoppabledomains/config@npm:latest": - version: 0.0.13 - resolution: "@unstoppabledomains/config@npm:0.0.13" +"@unstoppabledomains/config@npm:0.0.16, @unstoppabledomains/config@npm:latest": + version: 0.0.16 + resolution: "@unstoppabledomains/config@npm:0.0.16" dependencies: "@bugsnag/browser-performance": ^2.2.0 "@bugsnag/js": ^7.16.2 @@ -6282,7 +6282,7 @@ __metadata: "@types/lodash.merge": ^4.6.7 lodash: ^4.17.21 lodash.merge: ^4.6.2 - checksum: edf0b6a9fe30b61a4f7e731c7a205ac814b6757b74c6bbf164c47b92be308141c1ab397775bc5c6bda900f176f46c09fe04afc30a6429e41d14ccb684d1d35ca + checksum: 5d3ffc9068b1e62578a7bb97a119f1c95b6ff61df7e226952d3ce1bf648334f0dbc5f60fb80c4ae62080179af5a546c1f2cb13303d3116c9517d5a307802bb24 languageName: node linkType: hard @@ -6299,9 +6299,9 @@ __metadata: languageName: node linkType: hard -"@unstoppabledomains/ui-components@npm:0.0.51-browser-extension.6": - version: 0.0.51-browser-extension.6 - resolution: "@unstoppabledomains/ui-components@npm:0.0.51-browser-extension.6" +"@unstoppabledomains/ui-components@npm:0.0.51-browser-extension.8": + version: 0.0.51-browser-extension.8 + resolution: "@unstoppabledomains/ui-components@npm:0.0.51-browser-extension.8" dependencies: "@braintree/sanitize-url": ^6.0.4 "@emotion/server": ^11.4.0 @@ -6342,6 +6342,7 @@ __metadata: "@xmtp/content-type-text": ^1.0.0 "@xmtp/proto": ^3.62.1 "@xmtp/xmtp-js": 12.1.0 + abitype: ^1.0.6 bip322-js: ^1.1.0 bitcoin-address-validation: ^2.2.3 bluebird: ^3.7.2 @@ -6400,7 +6401,7 @@ __metadata: "@unstoppabledomains/ui-kit": ^0.3.24 notistack: ^2.0.5 react-query: ^3.39.3 - checksum: 9e57ff6e08a952c9180a45443df228999979b4ec17da7ced8d08918bd07ec084e36e4e00fe9e21715c68dbead776a75c9e74072a69996691c3687fc80016d749 + checksum: 81ed0c170b3b7b22a74f8b12718e2fde7b10484689e739e420ea3acfa98f561d632822e22bf97adbaedf749a2165929ed9fc2e8d302c976e5d1929c32acdbc48 languageName: node linkType: hard @@ -22263,8 +22264,8 @@ __metadata: "@types/react-dom": ^17.0.0 "@typescript-eslint/eslint-plugin": ^5.39.0 "@typescript-eslint/parser": ^5.39.0 - "@unstoppabledomains/config": 0.0.13 - "@unstoppabledomains/ui-components": 0.0.51-browser-extension.6 + "@unstoppabledomains/config": 0.0.16 + "@unstoppabledomains/ui-components": 0.0.51-browser-extension.8 "@unstoppabledomains/ui-kit": 0.3.24 abitype: ^1.0.6 assert: ^2.1.0 From 30d35b39482ed4d1de64bdecc30f7772f0f70d23 Mon Sep 17 00:00:00 2001 From: Aaron Quirk Date: Mon, 4 Nov 2024 14:32:23 -0500 Subject: [PATCH 2/7] typecheck --- src/lib/wallet/evm/provider.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/wallet/evm/provider.ts b/src/lib/wallet/evm/provider.ts index f8206df..d7b76df 100644 --- a/src/lib/wallet/evm/provider.ts +++ b/src/lib/wallet/evm/provider.ts @@ -5,7 +5,10 @@ import {getProviderUrl} from "@unstoppabledomains/ui-components/lib/wallet/evm/p export const getWeb3Provider = (chainId: number) => { const chainSymbol = Object.keys(config.BLOCKCHAINS).find(k => { - return config.BLOCKCHAINS[k].CHAIN_ID === chainId; + return ( + config.BLOCKCHAINS[k as keyof typeof config.BLOCKCHAINS].CHAIN_ID === + chainId + ); }); if (!chainSymbol) { throw new Error(`Configuration not found for chainId: ${chainId}`); From f06e4d702b5ca3021458e632e1ae2662598057ed Mon Sep 17 00:00:00 2001 From: Aaron Quirk Date: Mon, 4 Nov 2024 14:45:00 -0500 Subject: [PATCH 3/7] update unit test --- src/lib/wallet/isAscii.test.ts | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/lib/wallet/isAscii.test.ts diff --git a/src/lib/wallet/isAscii.test.ts b/src/lib/wallet/isAscii.test.ts new file mode 100644 index 0000000..0965e5f --- /dev/null +++ b/src/lib/wallet/isAscii.test.ts @@ -0,0 +1,7 @@ +import {isAscii} from "./isAscii"; + +describe("isAscii", () => { + it("returns true for ASCII text", () => { + expect(isAscii("abc123")).toBeTruthy(); + }); +}); From bf29c87b70aaf0b0da7384b046503283e2140895 Mon Sep 17 00:00:00 2001 From: Aaron Quirk Date: Mon, 4 Nov 2024 14:47:33 -0500 Subject: [PATCH 4/7] update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc7cde2..202b36b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ ## 3.1.38 +* Support for ERC-20 token management +* Support additional RPC methods to enable Uniswap transactions * Support for service worker background signing * Fix bug validating token decimals before transfer * Modify activity panel color palette From 6e271002ec89d0f099b24966c6598acdc05f4768 Mon Sep 17 00:00:00 2001 From: Aaron Quirk Date: Tue, 5 Nov 2024 09:50:51 -0500 Subject: [PATCH 5/7] bump packages --- package.json | 4 ++-- yarn.lock | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 7fe0dac..5208cb2 100644 --- a/package.json +++ b/package.json @@ -47,8 +47,8 @@ "@metamask/providers": "^17.1.2", "@types/react": "^17.0.0", "@types/react-dom": "^17.0.0", - "@unstoppabledomains/config": "0.0.16", - "@unstoppabledomains/ui-components": "0.0.51-browser-extension.8", + "@unstoppabledomains/config": "0.0.17", + "@unstoppabledomains/ui-components": "0.0.51-browser-extension.9", "@unstoppabledomains/ui-kit": "0.3.24", "abitype": "^1.0.6", "async-mutex": "^0.5.0", diff --git a/yarn.lock b/yarn.lock index 8523465..07582ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6271,9 +6271,9 @@ __metadata: languageName: node linkType: hard -"@unstoppabledomains/config@npm:0.0.16, @unstoppabledomains/config@npm:latest": - version: 0.0.16 - resolution: "@unstoppabledomains/config@npm:0.0.16" +"@unstoppabledomains/config@npm:0.0.17, @unstoppabledomains/config@npm:latest": + version: 0.0.17 + resolution: "@unstoppabledomains/config@npm:0.0.17" dependencies: "@bugsnag/browser-performance": ^2.2.0 "@bugsnag/js": ^7.16.2 @@ -6282,7 +6282,7 @@ __metadata: "@types/lodash.merge": ^4.6.7 lodash: ^4.17.21 lodash.merge: ^4.6.2 - checksum: 5d3ffc9068b1e62578a7bb97a119f1c95b6ff61df7e226952d3ce1bf648334f0dbc5f60fb80c4ae62080179af5a546c1f2cb13303d3116c9517d5a307802bb24 + checksum: 0b20b5e6b3ccad71b6ee0ed83efc696e9a4444c945ca63b0ba3f2636758a8de9c009652d859bbc488325c3f19bc74a6b10641ff3775b2d15b52e0a0e233c7b78 languageName: node linkType: hard @@ -6299,9 +6299,9 @@ __metadata: languageName: node linkType: hard -"@unstoppabledomains/ui-components@npm:0.0.51-browser-extension.8": - version: 0.0.51-browser-extension.8 - resolution: "@unstoppabledomains/ui-components@npm:0.0.51-browser-extension.8" +"@unstoppabledomains/ui-components@npm:0.0.51-browser-extension.9": + version: 0.0.51-browser-extension.9 + resolution: "@unstoppabledomains/ui-components@npm:0.0.51-browser-extension.9" dependencies: "@braintree/sanitize-url": ^6.0.4 "@emotion/server": ^11.4.0 @@ -6401,7 +6401,7 @@ __metadata: "@unstoppabledomains/ui-kit": ^0.3.24 notistack: ^2.0.5 react-query: ^3.39.3 - checksum: 81ed0c170b3b7b22a74f8b12718e2fde7b10484689e739e420ea3acfa98f561d632822e22bf97adbaedf749a2165929ed9fc2e8d302c976e5d1929c32acdbc48 + checksum: 9be156acf2b1a2b78ff8744381668a63c2a00bac1367037c0321a93d6f80f0852adfe0f6a7387f54d32afd681656478147eeb8154154997940e703551f5c6c02 languageName: node linkType: hard @@ -22264,8 +22264,8 @@ __metadata: "@types/react-dom": ^17.0.0 "@typescript-eslint/eslint-plugin": ^5.39.0 "@typescript-eslint/parser": ^5.39.0 - "@unstoppabledomains/config": 0.0.16 - "@unstoppabledomains/ui-components": 0.0.51-browser-extension.8 + "@unstoppabledomains/config": 0.0.17 + "@unstoppabledomains/ui-components": 0.0.51-browser-extension.9 "@unstoppabledomains/ui-kit": 0.3.24 abitype: ^1.0.6 assert: ^2.1.0 From b3dbea9bf489e43b40254bb91faeee4572575687 Mon Sep 17 00:00:00 2001 From: Aaron Quirk Date: Tue, 5 Nov 2024 10:58:22 -0500 Subject: [PATCH 6/7] bump packages --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 5208cb2..2842d7a 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "@types/react": "^17.0.0", "@types/react-dom": "^17.0.0", "@unstoppabledomains/config": "0.0.17", - "@unstoppabledomains/ui-components": "0.0.51-browser-extension.9", + "@unstoppabledomains/ui-components": "0.0.51-browser-extension.10", "@unstoppabledomains/ui-kit": "0.3.24", "abitype": "^1.0.6", "async-mutex": "^0.5.0", diff --git a/yarn.lock b/yarn.lock index 07582ef..aa979d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6299,9 +6299,9 @@ __metadata: languageName: node linkType: hard -"@unstoppabledomains/ui-components@npm:0.0.51-browser-extension.9": - version: 0.0.51-browser-extension.9 - resolution: "@unstoppabledomains/ui-components@npm:0.0.51-browser-extension.9" +"@unstoppabledomains/ui-components@npm:0.0.51-browser-extension.10": + version: 0.0.51-browser-extension.10 + resolution: "@unstoppabledomains/ui-components@npm:0.0.51-browser-extension.10" dependencies: "@braintree/sanitize-url": ^6.0.4 "@emotion/server": ^11.4.0 @@ -6401,7 +6401,7 @@ __metadata: "@unstoppabledomains/ui-kit": ^0.3.24 notistack: ^2.0.5 react-query: ^3.39.3 - checksum: 9be156acf2b1a2b78ff8744381668a63c2a00bac1367037c0321a93d6f80f0852adfe0f6a7387f54d32afd681656478147eeb8154154997940e703551f5c6c02 + checksum: 942daaa58b454b844d217096378b4c6ad8f9dc5abca48c3acda479cd98f0125e576c165eabc422fbe4fc0a840d85ad58c3641a7d77d2e8c7fc8910f3e3b88368 languageName: node linkType: hard @@ -22265,7 +22265,7 @@ __metadata: "@typescript-eslint/eslint-plugin": ^5.39.0 "@typescript-eslint/parser": ^5.39.0 "@unstoppabledomains/config": 0.0.17 - "@unstoppabledomains/ui-components": 0.0.51-browser-extension.9 + "@unstoppabledomains/ui-components": 0.0.51-browser-extension.10 "@unstoppabledomains/ui-kit": 0.3.24 abitype: ^1.0.6 assert: ^2.1.0 From 5244c3344617a427abc07f482d919f2f2b00113d Mon Sep 17 00:00:00 2001 From: Aaron Quirk Date: Tue, 5 Nov 2024 11:02:07 -0500 Subject: [PATCH 7/7] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 202b36b..1ce9acd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * Support for ERC-20 token management * Support additional RPC methods to enable Uniswap transactions * Support for service worker background signing +* Remove clutter from drop down menu * Fix bug validating token decimals before transfer * Modify activity panel color palette