From 7c8c13e44f18cb9b747573f435ccab310d0fb416 Mon Sep 17 00:00:00 2001 From: vignesha22 <82584664+vignesha22@users.noreply.github.com> Date: Thu, 21 Mar 2024 15:57:42 +0530 Subject: [PATCH] PRO-2182 - Added metadata api and Optimisations (#76) * added metadata api and optimisations * changes as per feedback --- admin_frontend/package-lock.json | 4 +- admin_frontend/package.json | 2 +- admin_frontend/src/components/Dashboard.jsx | 2 +- backend/indexer/EtherspotAbi.ts | 117 +- backend/package.json | 2 +- backend/src/abi/EtherspotAbi.ts | 1163 +++++++++---------- backend/src/constants/Pimlico.ts | 91 +- backend/src/paymaster/index.test.ts | 53 +- backend/src/paymaster/index.ts | 117 +- backend/src/paymaster/pimlico.ts | 19 +- backend/src/plugins/config.ts | 2 + backend/src/routes/index.ts | 66 +- backend/src/routes/metadata.ts | 108 ++ backend/src/server.ts | 6 +- backend/src/utils/common.ts | 27 + frontend/package-lock.json | 4 +- frontend/package.json | 2 +- 17 files changed, 988 insertions(+), 797 deletions(-) create mode 100644 backend/src/routes/metadata.ts diff --git a/admin_frontend/package-lock.json b/admin_frontend/package-lock.json index bd3c274..1cac3a6 100644 --- a/admin_frontend/package-lock.json +++ b/admin_frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "admin_frontend", - "version": "1.0.3", + "version": "1.1.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "admin_frontend", - "version": "1.0.3", + "version": "1.1.6", "dependencies": { "@emotion/react": "11.11.3", "@emotion/styled": "11.11.0", diff --git a/admin_frontend/package.json b/admin_frontend/package.json index a99ede5..39b1cf9 100644 --- a/admin_frontend/package.json +++ b/admin_frontend/package.json @@ -1,6 +1,6 @@ { "name": "admin_frontend", - "version": "1.1.5", + "version": "1.1.6", "private": true, "dependencies": { "@emotion/react": "11.11.3", diff --git a/admin_frontend/src/components/Dashboard.jsx b/admin_frontend/src/components/Dashboard.jsx index 8a8d092..2d63dad 100644 --- a/admin_frontend/src/components/Dashboard.jsx +++ b/admin_frontend/src/components/Dashboard.jsx @@ -83,7 +83,7 @@ const Dashboard = () => { method: "GET", } ); - const dataJson = data.json(); + const dataJson = await data.json(); setConfig(dataJson); setEdittedConfig(dataJson); let buffer; diff --git a/backend/indexer/EtherspotAbi.ts b/backend/indexer/EtherspotAbi.ts index 3674907..b0a8425 100644 --- a/backend/indexer/EtherspotAbi.ts +++ b/backend/indexer/EtherspotAbi.ts @@ -1,4 +1,4 @@ -export const EtherspotPaymasterAbi = [ +export default [ { "inputs": [ { @@ -124,51 +124,6 @@ export const EtherspotPaymasterAbi = [ "name": "SponsorSuccessful", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "paymaster", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "SponsorUnsuccessful", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "WhitelistInitialized", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "addToWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -197,26 +152,15 @@ export const EtherspotPaymasterAbi = [ }, { "inputs": [ - { - "internalType": "address", - "name": "_sponsor", - "type": "address" - }, { "internalType": "address", "name": "_account", "type": "address" } ], - "name": "check", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", + "name": "addToWhitelist", + "outputs": [], + "stateMutability": "nonpayable", "type": "function" }, { @@ -225,14 +169,19 @@ export const EtherspotPaymasterAbi = [ "internalType": "address", "name": "_sponsor", "type": "address" + }, + { + "internalType": "address", + "name": "_account", + "type": "address" } ], - "name": "checkSponsorFunds", + "name": "check", "outputs": [ { - "internalType": "uint256", + "internalType": "bool", "name": "", - "type": "uint256" + "type": "bool" } ], "stateMutability": "view", @@ -357,6 +306,25 @@ export const EtherspotPaymasterAbi = [ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "_sponsor", + "type": "address" + } + ], + "name": "getSponsorBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "owner", @@ -425,12 +393,12 @@ export const EtherspotPaymasterAbi = [ { "inputs": [ { - "internalType": "address", - "name": "_account", - "type": "address" + "internalType": "address[]", + "name": "_accounts", + "type": "address[]" } ], - "name": "remove", + "name": "removeBatchFromWhitelist", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -438,12 +406,12 @@ export const EtherspotPaymasterAbi = [ { "inputs": [ { - "internalType": "address[]", - "name": "_accounts", - "type": "address[]" + "internalType": "address", + "name": "_account", + "type": "address" } ], - "name": "removeBatch", + "name": "removeFromWhitelist", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -568,11 +536,6 @@ export const EtherspotPaymasterAbi = [ }, { "inputs": [ - { - "internalType": "address payable", - "name": "_sponsor", - "type": "address" - }, { "internalType": "uint256", "name": "_amount", @@ -597,4 +560,4 @@ export const EtherspotPaymasterAbi = [ "stateMutability": "nonpayable", "type": "function" } -] as const; +] as const; \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index dc95b85..1873640 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "arka", - "version": "1.1.5", + "version": "1.1.6", "description": "ARKA - (Albanian for Cashier's case) is the first open source Paymaster as a service software", "type": "module", "directories": { diff --git a/backend/src/abi/EtherspotAbi.ts b/backend/src/abi/EtherspotAbi.ts index 059f22e..d187cfc 100644 --- a/backend/src/abi/EtherspotAbi.ts +++ b/backend/src/abi/EtherspotAbi.ts @@ -1,600 +1,563 @@ -export default [ - { - "inputs": [ - { - "internalType": "contract IEntryPoint", - "name": "_entryPoint", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "paymaster", - "type": "address" - }, - { - "indexed": true, - "internalType": "address[]", - "name": "accounts", - "type": "address[]" - } - ], - "name": "AddedBatchToWhitelist", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "paymaster", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "AddedToWhitelist", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "paymaster", - "type": "address" - }, - { - "indexed": true, - "internalType": "address[]", - "name": "accounts", - "type": "address[]" - } - ], - "name": "RemovedBatchFromWhitelist", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "paymaster", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "RemovedFromWhitelist", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "paymaster", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "SponsorSuccessful", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "paymaster", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "SponsorUnsuccessful", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "WhitelistInitialized", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "addToWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "_accounts", - "type": "address[]" - } - ], - "name": "addBatchToWhitelist", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint32", - "name": "unstakeDelaySec", - "type": "uint32" - } - ], - "name": "addStake", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_sponsor", - "type": "address" - }, - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "check", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_sponsor", - "type": "address" - } - ], - "name": "checkSponsorFunds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "depositFunds", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "entryPoint", - "outputs": [ - { - "internalType": "contract IEntryPoint", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getDeposit", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "initCode", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "callGasLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "verificationGasLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "preVerificationGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxFeePerGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxPriorityFeePerGas", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "paymasterAndData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct UserOperation", - "name": "userOp", - "type": "tuple" - }, - { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" - }, - { - "internalType": "uint48", - "name": "validAfter", - "type": "uint48" - } - ], - "name": "getHash", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "paymasterAndData", - "type": "bytes" - } - ], - "name": "parsePaymasterAndData", - "outputs": [ - { - "internalType": "uint48", - "name": "validUntil", - "type": "uint48" - }, - { - "internalType": "uint48", - "name": "validAfter", - "type": "uint48" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "enum IPaymaster.PostOpMode", - "name": "mode", - "type": "uint8" - }, - { - "internalType": "bytes", - "name": "context", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "actualGasCost", - "type": "uint256" - } - ], - "name": "postOp", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_account", - "type": "address" - } - ], - "name": "remove", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "_accounts", - "type": "address[]" - } - ], - "name": "removeBatch", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "unlockStake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "initCode", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "callData", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "callGasLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "verificationGasLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "preVerificationGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxFeePerGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxPriorityFeePerGas", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "paymasterAndData", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "signature", - "type": "bytes" - } - ], - "internalType": "struct UserOperation", - "name": "userOp", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "userOpHash", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "maxCost", - "type": "uint256" - } - ], - "name": "validatePaymasterUserOp", - "outputs": [ - { - "internalType": "bytes", - "name": "context", - "type": "bytes" - }, - { - "internalType": "uint256", - "name": "validationData", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address payable", - "name": "_sponsor", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_amount", - "type": "uint256" - } - ], - "name": "withdrawFunds", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address payable", - "name": "withdrawAddress", - "type": "address" - } - ], - "name": "withdrawStake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ] as const; \ No newline at end of file +export const EtherspotPaymasterAbi = [ + { + "inputs": [ + { + "internalType": "contract IEntryPoint", + "name": "_entryPoint", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "paymaster", + "type": "address" + }, + { + "indexed": true, + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + } + ], + "name": "AddedBatchToWhitelist", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "paymaster", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddedToWhitelist", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "paymaster", + "type": "address" + }, + { + "indexed": true, + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + } + ], + "name": "RemovedBatchFromWhitelist", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "paymaster", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "RemovedFromWhitelist", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "paymaster", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "SponsorSuccessful", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_accounts", + "type": "address[]" + } + ], + "name": "addBatchToWhitelist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "unstakeDelaySec", + "type": "uint32" + } + ], + "name": "addStake", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "addToWhitelist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_sponsor", + "type": "address" + }, + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "check", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "depositFunds", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "entryPoint", + "outputs": [ + { + "internalType": "contract IEntryPoint", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "initCode", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "callGasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "verificationGasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "preVerificationGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPriorityFeePerGas", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "paymasterAndData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct UserOperation", + "name": "userOp", + "type": "tuple" + }, + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "validAfter", + "type": "uint48" + } + ], + "name": "getHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_sponsor", + "type": "address" + } + ], + "name": "getSponsorBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "paymasterAndData", + "type": "bytes" + } + ], + "name": "parsePaymasterAndData", + "outputs": [ + { + "internalType": "uint48", + "name": "validUntil", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "validAfter", + "type": "uint48" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum IPaymaster.PostOpMode", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "context", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "actualGasCost", + "type": "uint256" + } + ], + "name": "postOp", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_accounts", + "type": "address[]" + } + ], + "name": "removeBatchFromWhitelist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_account", + "type": "address" + } + ], + "name": "removeFromWhitelist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unlockStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "initCode", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "callData", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "callGasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "verificationGasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "preVerificationGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPriorityFeePerGas", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "paymasterAndData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "internalType": "struct UserOperation", + "name": "userOp", + "type": "tuple" + }, + { + "internalType": "bytes32", + "name": "userOpHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "maxCost", + "type": "uint256" + } + ], + "name": "validatePaymasterUserOp", + "outputs": [ + { + "internalType": "bytes", + "name": "context", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "validationData", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "withdrawFunds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "withdrawAddress", + "type": "address" + } + ], + "name": "withdrawStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] as const; diff --git a/backend/src/constants/Pimlico.ts b/backend/src/constants/Pimlico.ts index ca54699..b69d011 100644 --- a/backend/src/constants/Pimlico.ts +++ b/backend/src/constants/Pimlico.ts @@ -1,21 +1,17 @@ export const TOKEN_ADDRESS: Record> = { 1: { - DAI: "0x6b175474e89094c44da98b954eedeac495271d0f", - USDC: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", - USDT: "0xdac17f958d2ee523a2206206994597c13d831ec7" - }, - 5: { - DAI: "0x11fE4B6AE13d2a6055C8D9cF65c55bac32B5d844", - USDC: "0x07865c6E87B9F70255377e024ace6630C1Eaa37F" + USDC: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", }, 56: { USDC: "0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d", - USDT: "0x55d398326f99059ff775485246999027b3197955" + }, + 100: { + USDC: "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83" }, 137: { - DAI: "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063", - USDC: "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", - USDT: "0xc2132d05d31c914a87c6611c10748aeb04b58e8f" + USDC: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + eUSDC: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", + USDT: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F" }, 42161: { DAI: "0xda10009cbd5d07dd0cecc66161fc93d7c9000da1", @@ -33,6 +29,12 @@ export const TOKEN_ADDRESS: Record> = { }, 84531: { USDC: "0x1B85deDe8178E18CdE599B4C9d913534553C3dBf" + }, + 8453: { + USDC: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" + }, + 59144: { + USDC: "0x176211869ca2b568f2a7d4ee941e073a821ee1ff" } } @@ -98,17 +100,82 @@ export const ORACLE_ADDRESS: Record> = { * Example Structure for adding deployed erc20 paymasters on AWS secrets manager */ export const CustomDeployedPaymasters: Record> = { + "137": { + "USDT": "0xFB8A7D1786E01f31Fc6466A48243Ca9FF0820cCB" + }, "10": { "USDC": "0x99fB8d618F52a42049776899D5c07241D344a8A4", "DAI": "0x3bE5380ec8cfe159f0525d16d11E9Baba516C40c", - "USDT": "0x9102889001d0901b3d9123651d492e52ce772C6b" + "USDT": "0x9102889001d0901b3d9123651d492e52ce772C6b", + "WETH": "0x875329626E55Cc890b6444b497B1E369f45379F9", + "LINK": "0xD5FD5b4AeF90055a55Dd97A3cCA10c18A653E16b", + "UNI": "0xC016585AbCdBD09AB2b9E1C782486B06b8bbEeF7", + "FRAX": "0x950BD6AF4EEe695c1Be4D4335E8710B511356e59" }, "420": { "LINK": "0x53F48579309f8dBfFE4edE921C50200861C2482a" }, "421613": { "LINK": "0x0a6Aa1Bd30D6954cA525315287AdeeEcbb6eFB59" + }, + "42161": { + "DAI": "0x03A4Fac637301915660192f59ac31117441Ab13e", + "USDT": "0xA1748d4A93e361e186B7bC19a733f79601315aDe", + "WETH": "0xB55B04045fA72374bF94FCB32cDd63bD81cC4b07", + "LINK": "0x667d2fc02c34a557A87EC7F62FeAe3CA2BabD5d3", + "UNI": "0xde07AF31A650cd77c5F2A69501e7d90c4836F660", + "FRAX": "0xE0221Db5bF2F3C22d6639a749B764f52f5B05dfb" + }, + "114": { + "USDC": "0x8b067387ec0B922483Eadb771bc9290194685522" + }, + "14": { + "eUSDT": "0x6Bb048981E67f1a0aD41c0BD05635244d3ADaA2c" + }, + "5001": { + "USDCT": "0x6Ea25cbb60360243E871dD935225A293a78704a8" + }, + "5000": { + "USDC": "0x5E23Cf2A0218fA9C23FFF1BD533061927D393926" } } +export const PAYMASTER_ADDRESS: Record> = { + 1: { + USDC: "0x0000000000fABFA8079AB313D1D14Dcf4D15582a" + }, + 56: { + USDC: "0x0000000000db7995889f54d72dac9d36a9f7f467" + }, + 100: { + USDC: "0x000000000034b78bfe02be30ae4d324c8702803d" + }, + 137: { + eUSDC: "0xa683b47e447De6c8A007d9e294e87B6Db333Eb18", + USDC: "0x00000000003011eef3f79892ba3d521e5ba5c5c0" + }, + 8453: { + USDC: "0x939263eafe57038a072cb4edd6b25dd81a8a6c56" + }, + 84532: { + USDC: "0x0000000000dd6dd248ab5487218e1c2d7fbb29c9" + }, + 42161: { + eUSDC: "0x49EE41bC335Fb36be46A17307dcFe536A3494644", + USDC: "0x000000000058e13d711bb4706bf822a79c35d8b1" + }, + 59144: { + USDC: "0x0000000000Cf745CB08EE7A6F0A2D74BB942E414" + }, + 10: { + USDC: "0x0000000000fce6614d3c6f679e48c9cdd09aa634" + }, + 11155111: { + USDC: "0x0000000000325602a77416a16136fdafd04b299f" + }, + 80001: { + USDC: "0x000000000009B901DeC1aaB9389285965F49D387" + }, +} + export const bytecode = "0x610120604081815234620004105760a08262002084803803809162000025828562000415565b833981010312620004105781516001600160a01b0380821693918490036200041057602090818301519080821682036200041057620000668585016200044f565b93608062000077606083016200044f565b9101519682881693848903620004105762000092336200047f565b6080528060a0528560e0526101009782895265030d4000864760c51b60018060c01b036001541617600155600094338587541603620003ce57156200037b57620000dc906200047f565b86519586868163313ce56760e01b9485825260049a8b915afa90811562000371579060ff9187916200034f575b5016604d81116200033c5784918791600a0a60c052888a5180948193878352165afa908115620003325760089160ff91879162000310575b501603620002ba5790858592885194859384928352165afa918215620002af5760089260ff92906200027b575b5016036200022157505051611bbd9182620004c7833960805182818161074c015281816108900152818161096501528181610a2201528181610ad3015281816112c00152818161138a01526114d7015260a05182818161017a0152818161030201528181610beb0152611839015260c051828181610e9f015281816112040152611749015260e051828181610ddb01528181610e3301526116d30152518181816106e501528181610e5c01526116fc0152f35b608492519162461bcd60e51b8352820152603160248201527f50502d4552433230203a206e6174697665206173736574206f7261636c6520646044820152700cac6d2dac2d8e640daeae6e840c4ca407607b1b6064820152fd5b620002a09150843d8611620002a7575b62000297818362000415565b81019062000464565b386200016e565b503d6200028b565b8551903d90823e3d90fd5b865162461bcd60e51b8152808701869052602a60248201527f50502d4552433230203a20746f6b656e206f7261636c6520646563696d616c73604482015269040daeae6e840c4ca40760b31b6064820152608490fd5b6200032b9150883d8a11620002a75762000297818362000415565b3862000141565b88513d87823e3d90fd5b634e487b7160e01b865260118852602486fd5b6200036a9150883d8a11620002a75762000297818362000415565b3862000109565b89513d88823e3d90fd5b875162461bcd60e51b815260048101879052602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b6064878a519062461bcd60e51b825280600483015260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b600080fd5b601f909101601f19168101906001600160401b038211908210176200043957604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036200041057565b9081602091031262000410575160ff81168103620004105790565b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a356fe6040608081526004908136101561001557600080fd5b600091823560e01c9081630396cb601461133557838263205c287814611267575081633a34c83f146112275781633b97e856146111ce5781633c2154bc14610f7c5781633e04619d14610f36578163673a7e2814610dff5781636c5ec25c14610d90578163715018a614610cf35781638da5cb5b14610ca2578163914e245a14610c4b5781639dbdb97714610c105781639e281a9814610b8e578163a9a2340914610af7578163b0d691fe14610a8857838263bb9fe6bf146109d2578263c23a5cea1461090b57508163c399ec8814610817578163cdcf4b9b146107db57838263d0e30db01461070957508163efb1ad5d1461069a578163f2fde38b14610560578163f465c77e146101a2575063fc0c546a1461013157600080fd5b3461019e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5080fd5b9050823461055d576060917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc91838336011261055d5781359167ffffffffffffffff9586841161055957610160848301958536030112610559576102046114c0565b6001549177ffffffffffffffffffffffffffffffffffffffffffffffff831680156104fc576101248601907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec61025a838a611634565b905001967effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdf881661049f579069d3c21bcecceda10000009160e463ffffffff60c098891c16910135619c40026044350102020490602080971461041f575b506102c18761168f565b96835197828a52308552891b602c526f23b872dd000000000000000000000000600c5286866064601c8273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af13d15600188511417161561041457906103637fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092878b5289865261168f565b9087890152881b16828701526034865286860197868910908911176103e6575086815286528351928360a0860152825b8481106103d4575050838301018190526080830152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168101030190f35b85810180830151908401528101610393565b6041907f4e487b71000000000000000000000000000000000000000000000000000000006000525260246000fd5b8686637939f4248152fd5b6104299088611634565b60341161049b5760140135811161044057896102b7565b50848060649351927f08c379a000000000000000000000000000000000000000000000000000000000845283015260248201527f50502d4552433230203a20746f6b656e20616d6f756e7420746f6f20686967686044820152fd5b8580fd5b60648460208751917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601e60248201527f50502d4552433230203a20696e76616c69642064617461206c656e67746800006044820152fd5b50602060649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601860248201527f50502d4552433230203a207072696365206e6f742073657400000000000000006044820152fd5b8280fd5b80fd5b9050346105595760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261055957610599611419565b906105a261155d565b73ffffffffffffffffffffffffffffffffffffffff809216928315610617575050600054827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b90602060849251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b50503461019e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b809184827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107d75773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691823b156107d257839060248351809581937fb760faf9000000000000000000000000000000000000000000000000000000008352309083015234905af19081156107c957506107b95750f35b6107c29061143c565b61055d5780f35b513d84823e3d90fd5b505050fd5b5050fd5b50503461019e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e5760209051620f42408152f35b9190503461055957827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610559578051917f70a08231000000000000000000000000000000000000000000000000000000008352309083015260208260248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa9182156109015783926108ca575b6020838351908152f35b9091506020813d82116108f9575b816108e56020938361147f565b8101031261055957602092505190386108c0565b3d91506108d8565b81513d85823e3d90fd5b809184346107d75760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107d757610945611419565b61094d61155d565b73ffffffffffffffffffffffffffffffffffffffff807f000000000000000000000000000000000000000000000000000000000000000016803b1561049b57859283602492865197889586947fc23a5cea00000000000000000000000000000000000000000000000000000000865216908401525af19081156107c957506107b95750f35b809184346107d757827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107d757610a0b61155d565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691823b156107d257839283918351809581937fbb9fe6bf0000000000000000000000000000000000000000000000000000000083525af19081156107c957506107b95750f35b50503461019e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b83903461019e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e578035906003821015610559576024359067ffffffffffffffff90818311610b8a5736602384011215610b8a57820135908111610b86573660248284010111610b8657610b8392610b766114c0565b60246044359301906116b0565b80f35b8380fd5b8480fd5b50503461019e577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261055d57610b83610bc8611419565b610bd061155d565b6024359073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016611b68565b50503461019e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e5760209051619c408152f35b50503461019e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e5760209077ffffffffffffffffffffffffffffffffffffffffffffffff600154169051908152f35b50503461019e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e5773ffffffffffffffffffffffffffffffffffffffff60209254169051908152f35b833461055d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261055d57610d2a61155d565b600073ffffffffffffffffffffffffffffffffffffffff81547fffffffffffffffffffffffff000000000000000000000000000000000000000081168355167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50503461019e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b833461055d57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261055d57610e577f00000000000000000000000000000000000000000000000000000000000000006118f7565b610e807f00000000000000000000000000000000000000000000000000000000000000006118f7565b9077ffffffffffffffffffffffffffffffffffffffffffffffff9182807f00000000000000000000000000000000000000000000000000000000000000001691168382820216918183041490151715610f0a5790610edd916115dc565b167fffffffffffffffff000000000000000000000000000000000000000000000000600154161760015580f35b6024846011877f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b50503461019e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e5760209063ffffffff60015460c01c169051908152f35b83833461019e57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e57610fb4611406565b926024359363ffffffff90818616918287036111c957610fd261155d565b81169262124f80841161116c57620f424080851061110f57831161108d57507ffed7660357162e9e060534e05beba94ac6e3bfb17b1f793bd7350aaed0e9e8c4949577ffffffffffffffffffffffffffffffffffffffffffffffff7bffffffff0000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000006001549360e01b169360c01b169116171760015582519182526020820152a180f35b60849060208651917f08c379a00000000000000000000000000000000000000000000000000000000083528201526024808201527f50502d4552433230203a20757064617465207468726573686f6c6420746f6f2060448201527f68696768000000000000000000000000000000000000000000000000000000006064820152fd5b60648260208851917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602060248201527f50502d4552433230203a207072696365206d61726b65757020746f6f206c6f776044820152fd5b60649060208651917f08c379a0000000000000000000000000000000000000000000000000000000008352820152602060248201527f50502d4552433230203a207072696365206d61726b757020746f6f20686967686044820152fd5b600080fd5b50503461019e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e57602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b50503461019e57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019e5760209060015460e01c9051908152f35b809184346107d757807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107d7576112a0611419565b6112a861155d565b73ffffffffffffffffffffffffffffffffffffffff807f000000000000000000000000000000000000000000000000000000000000000016803b1561049b57859283604492865197889586947f205c2878000000000000000000000000000000000000000000000000000000008652169084015260243560248401525af19081156107c957506107b95750f35b91905060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610559578261136b611406565b61137361155d565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b156105595763ffffffff91602491855196879485937f0396cb60000000000000000000000000000000000000000000000000000000008552169083015234905af19081156107c957506113fd575080f35b610b839061143c565b6004359063ffffffff821682036111c957565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036111c957565b67ffffffffffffffff811161145057604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761145057604052565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036114ff57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f53656e646572206e6f7420456e747279506f696e7400000000000000000000006044820152fd5b73ffffffffffffffffffffffffffffffffffffffff60005416330361157e57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b9077ffffffffffffffffffffffffffffffffffffffffffffffff80911691821561160557160490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156111c9570180359067ffffffffffffffff82116111c9576020019181360383136111c957565b8115611605570490565b3573ffffffffffffffffffffffffffffffffffffffff811681036111c95790565b92919260038110156118b1576002146118ac5769d3c21bcecceda10000006116f77f00000000000000000000000000000000000000000000000000000000000000006118f7565b6117207f00000000000000000000000000000000000000000000000000000000000000006118f7565b9060015461177077ffffffffffffffffffffffffffffffffffffffffffffffff928380841695817f00000000000000000000000000000000000000000000000000000000000000001602166115dc565b918160e01c921691620f4240808402918561178b8185611685565b82840110938415611894575b50505050611864575b505063ffffffff60015460c01c163a619c4002850102020492806020116111c957813584811161180c575b506034116111c95760206040917f472a42a044527b87df02c0ce8e6c00c0057fac40d6c424c93c24b02322eb14b593835195865282860152013560601c92a2565b816034116111c9578461185e9103602084013560601c73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016611b68565b386117cb565b8192507fffffffffffffffff000000000000000000000000000000000000000000000000161760015538806117a0565b6118a092939450611685565b91031138808581611797565b505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b519069ffffffffffffffffffff821682036111c957565b60a073ffffffffffffffffffffffffffffffffffffffff916004604051809481937ffeaf968c000000000000000000000000000000000000000000000000000000008352165afa8015611b5c576000809281908293611b06575b506000841315611aa8577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd5d00420190428211611a795710611a1b5769ffffffffffffffffffff8091169116106119bd5777ffffffffffffffffffffffffffffffffffffffffffffffff1690565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f50502d4552433230203a205374616c65207072696365000000000000000000006044820152fd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f50502d4552433230203a20496e636f6d706c65746520726f756e6400000000006044820152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f50502d4552433230203a20436861696e6c696e6b207072696365203c3d2030006044820152fd5b935050905060a0823d8211611b54575b81611b2360a0938361147f565b8101031261055d5750611b35816118e0565b6020820151611b4b6080606085015194016118e0565b91909238611951565b3d9150611b16565b6040513d6000823e3d90fd5b60109260209260145260345260446000938480936fa9059cbb00000000000000000000000082525af13d156001835114171615611ba457603452565b806390b8ec1860209252fdfea164736f6c6343000812000a"; diff --git a/backend/src/paymaster/index.test.ts b/backend/src/paymaster/index.test.ts index a9e1524..9236ac7 100644 --- a/backend/src/paymaster/index.test.ts +++ b/backend/src/paymaster/index.test.ts @@ -1,13 +1,17 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { ethers, Wallet } from "ethers"; +import { ethers, providers, Wallet } from "ethers"; import { Paymaster } from "./index.js"; +import { PAYMASTER_ADDRESS } from "../constants/Pimlico.js"; describe('Paymaster on Mumbai', () => { - const paymaster = new Paymaster(); + const paymaster = new Paymaster('10'); const paymasterAddress = '0x8350355c08aDAC387b443782124A30A8942BeC2e'; // Mumbai Etherspot Paymaster Address const entryPointAddress = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // EntryPoint v0.6 as default const bundlerUrl = 'https://mumbai-bundler.etherspot.io'; + const chainId = 80001; // Mumbai chainId const relayerKey = '0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb2'; // Testing wallet private key only has Mumbai funds in it + const provider = new providers.JsonRpcProvider(bundlerUrl); + const signer = new Wallet(relayerKey, provider) const userOp = { sender: '0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321', nonce: '0x1', @@ -18,7 +22,7 @@ describe('Paymaster on Mumbai', () => { maxFeePerGas: '0x6fc23ac10', maxPriorityFeePerGas: '0x6fc23ac00', paymasterAndData: '0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', - signature: '0x0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', + signature: '0x', preVerificationGas: '0xc6c4' }; @@ -26,8 +30,7 @@ describe('Paymaster on Mumbai', () => { const Mock_Valid_Until = '0x00000000deadbeef'; // max value const Mock_Valid_After = '0x0000000000001234'; // min value try { - const signResponse = await paymaster.sign(userOp, Mock_Valid_Until, Mock_Valid_After, entryPointAddress, paymasterAddress, bundlerUrl, relayerKey); - + const signResponse = await paymaster.sign(userOp, Mock_Valid_Until, Mock_Valid_After, entryPointAddress, paymasterAddress, bundlerUrl, signer); try { expect(signResponse).toHaveProperty('paymasterAndData'); } catch (e) { @@ -59,7 +62,8 @@ describe('Paymaster on Mumbai', () => { test('SMOKE: validate the pimlico function with valid details', async () => { const gasToken = 'USDC'; try { - const pimlicoResponse = await paymaster.pimlico(userOp, gasToken, bundlerUrl, entryPointAddress, null); + const tokenPaymasterAddress = PAYMASTER_ADDRESS[chainId][gasToken]; + const pimlicoResponse = await paymaster.pimlico(userOp, bundlerUrl, entryPointAddress, tokenPaymasterAddress); try { expect(pimlicoResponse).toHaveProperty('paymasterAndData'); @@ -93,7 +97,7 @@ describe('Paymaster on Mumbai', () => { test('SMOKE: validate the pimlicoAddress function with valid details', async () => { const gasToken = 'USDC'; try { - const pimlicoAddressResponse = await paymaster.pimlicoAddress(gasToken, bundlerUrl, entryPointAddress); + const pimlicoAddressResponse = await paymaster.pimlicoAddress(gasToken, chainId); try { expect(pimlicoAddressResponse).toHaveProperty('message'); @@ -142,11 +146,11 @@ describe('Paymaster on Mumbai', () => { const Mock_Valid_Until = '0x00000000deadbeef'; const Mock_Valid_After = '0x0000000000001234'; try { - await paymaster.sign(userOp, Mock_Valid_Until, Mock_Valid_After, entryPointAddress, paymasterAddress, bundlerUrl, relayerKey); + await paymaster.sign(userOp, Mock_Valid_Until, Mock_Valid_After, entryPointAddress, paymasterAddress, bundlerUrl, signer); fail('The sign function is worked, however the sender address is invalid.') } catch (e: any) { - const actualMessage = 'Transaction Execution reverted'; + const actualMessage = 'Please contact support team RawErrorMsg:invalid address'; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { console.log('The sender address is invalid while using the sign function.') @@ -161,10 +165,10 @@ describe('Paymaster on Mumbai', () => { const gasToken = 'USDC'; const address = ethers.Wallet.createRandom(); // random address try { - await paymaster.pimlico(userOp, gasToken, bundlerUrl, entryPointAddress, address.toString()); // invalid custom paymaster address + await paymaster.pimlico(userOp, bundlerUrl, entryPointAddress, address.toString()); // invalid custom paymaster address fail('The pimlico function is worked, however the customPaymasterAddress is invalid.') } catch (e: any) { - const actualMessage = 'Transaction Execution reverted network does not support ENS'; + const actualMessage = 'Please contact support team RawErrorMsg: network does not support ENS'; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { console.log('The customPaymasterAddress is invalid while using the pimlico function.') @@ -186,15 +190,15 @@ describe('Paymaster on Mumbai', () => { maxFeePerGas: '0x6fc23ac10', maxPriorityFeePerGas: '0x6fc23ac00', paymasterAndData: '0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', - signature: '0x0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', + signature: '0x', preVerificationGas: '0xc6c4' }; try { - await paymaster.pimlico(userOp, gasToken, bundlerUrl, entryPointAddress, null); + await paymaster.pimlico(userOp, bundlerUrl, entryPointAddress, PAYMASTER_ADDRESS[chainId][gasToken]); fail('The pimlico function is worked, however the sender address is invalid.') } catch (e: any) { - const actualMessage = 'Transaction Execution reverted'; + const actualMessage = ' Please contact support team RawErrorMsg: invalid address'; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { console.log('The sender address is invalid while using the pimlico function.') @@ -204,23 +208,6 @@ describe('Paymaster on Mumbai', () => { } }) - test('REGRESSION: validate the pimlicoAddress function with invalid bundlerUrl', async () => { - const gasToken = 'USDC'; - const bundlerUrl = 'http://mumbai-bundler.etherspot.io'; // invalid bundlerUrl - try { - await paymaster.pimlicoAddress(gasToken, bundlerUrl, entryPointAddress); - fail('The pimlicoAddress function is worked, however the bundlerUrl is invalid.') - } catch (e: any) { - const actualMessage = 'could not detect network'; - const expectedMessage = e.message; - if (expectedMessage.includes(actualMessage)) { - console.log('The bundlerUrl is invalid while using the pimlicoAddress function.') - } else { - fail('The respective validation is not displayed for invalid bundlerUrl while using the pimlicoAddress function.') - } - } - }) - test('REGRESSION: validate the whitelistAddresses function with not whitelisted address', async () => { const wallet = ethers.Wallet.createRandom(); const address = [wallet.address]; // not whitelisted address @@ -260,7 +247,7 @@ describe('Paymaster on Mumbai', () => { await paymaster.whitelistAddresses(address, paymasterAddress, bundlerUrl, relayerKey); fail('Address is whitelisted, however the relayerKey is invalid.') } catch (e: any) { - const actualMessage = 'Error while submitting transaction'; + const actualMessage = 'Please try again later or contact support team RawErrorMsg: hex data is odd-length'; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { console.log('The relayerKey is invalid while whitelisting the address.') @@ -322,7 +309,7 @@ describe('Paymaster on Mumbai', () => { await paymaster.deposit(amount, paymasterAddress, bundlerUrl, relayerKey); fail('The deposite action is performed with invalid amount.') } catch (e: any) { - const actualMessage = 'Error while submitting transaction'; + const actualMessage = 'Balance is less than the amount to be deposited'; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { console.log('The amount is invalid while performing the deposit.') diff --git a/backend/src/paymaster/index.ts b/backend/src/paymaster/index.ts index 066a1ca..49e2c92 100644 --- a/backend/src/paymaster/index.ts +++ b/backend/src/paymaster/index.ts @@ -1,14 +1,16 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { providers, Wallet, ethers, Contract } from 'ethers'; +import { providers, Wallet, ethers, Contract, BigNumber } from 'ethers'; import { arrayify, defaultAbiCoder, hexConcat } from 'ethers/lib/utils.js'; import abi from "../abi/EtherspotAbi.js"; import { PimlicoPaymaster, getERC20Paymaster } from './pimlico.js'; import ErrorMessage from '../constants/ErrorMessage.js'; +import { PAYMASTER_ADDRESS } from '../constants/Pimlico.js'; export class Paymaster { + feeMarkUp: BigNumber; - constructor() { - // + constructor(feeMarkUp: string) { + this.feeMarkUp = ethers.utils.parseUnits(feeMarkUp, 'gwei'); } async getPaymasterAndData(userOp: any, validUntil: string, validAfter: string, paymasterContract: Contract, signer: Wallet) { @@ -59,15 +61,36 @@ export class Paymaster { } } - async pimlico(userOp: any, gasToken: string, bundlerRpc: string, entryPoint: string, customPaymasterAddress: string | null) { + async pimlico(userOp: any, bundlerRpc: string, entryPoint: string, PaymasterAddress: string) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - let erc20Paymaster; - if (customPaymasterAddress) erc20Paymaster = new PimlicoPaymaster(customPaymasterAddress, provider) - else erc20Paymaster = await getERC20Paymaster(provider, gasToken, entryPoint) + const erc20Paymaster = new PimlicoPaymaster(PaymasterAddress, provider) if (!userOp.signature) userOp.signature = '0x'; - let paymasterAndData = await erc20Paymaster.generatePaymasterAndData(userOp) + + // The minimum ABI to get the ERC20 Token balance + const minABI = [ + // balanceOf + { + constant: true, + + inputs: [{ name: '_owner', type: 'address' }], + + name: 'balanceOf', + + outputs: [{ name: 'balance', type: 'uint256' }], + + type: 'function', + }, + ] + const tokenAmountRequired = await erc20Paymaster.calculateTokenAmount(userOp); + const tokenContract = new Contract(await erc20Paymaster.tokenAddress, minABI, provider) + const tokenBalance = await tokenContract.balanceOf(userOp.sender); + + if (tokenAmountRequired.gte(tokenBalance)) throw new Error(`The required token amount ${tokenAmountRequired.toString()} is more than what the sender has ${tokenBalance}`) + + let paymasterAndData = await erc20Paymaster.generatePaymasterAndDataForTokenAmount(userOp, tokenAmountRequired) userOp.paymasterAndData = paymasterAndData; + const response = await provider.send('eth_estimateUserOperationGas', [userOp, entryPoint]); userOp.verificationGasLimit = ethers.BigNumber.from(response.verificationGasLimit).add(100000).toString(); userOp.preVerificationGas = response.preVerificationGas; @@ -81,16 +104,15 @@ export class Paymaster { callGasLimit: response.callGasLimit, }; } catch (err: any) { + if (err.message.includes('The required token amount')) throw new Error(err.message); throw new Error('Failed to process request to bundler. Please contact support team RawErrorMsg: ' + err.message) } } - async pimlicoAddress(gasToken: string, bundlerRpc: string, entryPoint: string) { + async pimlicoAddress(gasToken: string, chainId: number) { try { - const provider = new providers.JsonRpcProvider(bundlerRpc); - const erc20Paymaster = await getERC20Paymaster(provider, gasToken, entryPoint) return { - message: erc20Paymaster.paymasterAddress + message: PAYMASTER_ADDRESS[chainId][gasToken] ?? 'Requested Token Paymaster is not available/deployed', } } catch (err: any) { throw new Error(err.message) @@ -109,14 +131,30 @@ export class Paymaster { } } const encodedData = paymasterContract.interface.encodeFunctionData('addBatchToWhitelist', [address]); - const tx = await signer.sendTransaction({ to: paymasterAddress, data: encodedData }); + const feeData = await provider.getFeeData(); + let tx: providers.TransactionResponse; + if (!feeData.maxFeePerGas) { + tx = await signer.sendTransaction({ + to: paymasterAddress, + data: encodedData, + gasPrice: feeData.gasPrice ? feeData.gasPrice.add(this.feeMarkUp) : undefined, + }) + } else { + tx = await signer.sendTransaction({ + to: paymasterAddress, + data: encodedData, + maxFeePerGas: feeData.maxFeePerGas ? feeData.maxFeePerGas.add(this.feeMarkUp) : undefined, + maxPriorityFeePerGas: feeData.maxPriorityFeePerGas ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) : undefined, + type: 2, + }); + } await tx.wait(); return { message: `Successfully whitelisted with transaction Hash ${tx.hash}` }; } catch (err: any) { - if (err.message.includes('already whitelisted')) throw new Error(err); - throw new Error(ErrorMessage.ERROR_ON_SUBMITTING_TXN); + if (err.message.includes('already whitelisted')) throw new Error(err.message); + throw new Error(ErrorMessage.ERROR_ON_SUBMITTING_TXN + ` RawErrorMsg: ${err.message}`); } } @@ -131,14 +169,30 @@ export class Paymaster { throw new Error(`${address[i]} is not whitelisted`) } } - const encodedData = paymasterContract.interface.encodeFunctionData('removeBatchToWhitelist', [address]); - const tx = await signer.sendTransaction({ to: paymasterAddress, data: encodedData }); + const encodedData = paymasterContract.interface.encodeFunctionData('removeBatchFromWhitelist', [address]); + const feeData = await provider.getFeeData(); + let tx: providers.TransactionResponse; + if (!feeData.maxFeePerGas) { + tx = await signer.sendTransaction({ + to: paymasterAddress, + data: encodedData, + gasPrice: feeData.gasPrice ? feeData.gasPrice.add(this.feeMarkUp) : undefined, + }) + } else { + tx = await signer.sendTransaction({ + to: paymasterAddress, + data: encodedData, + maxFeePerGas: feeData.maxFeePerGas ? feeData.maxFeePerGas.add(this.feeMarkUp) : undefined, + maxPriorityFeePerGas: feeData.maxPriorityFeePerGas ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) : undefined, + type: 2, + }); + } await tx.wait(); return { message: `Successfully removed whitelisted addresses with transaction Hash ${tx.hash}` }; } catch (err: any) { - if (err.message.includes('is not whitelisted')) throw new Error(err); + if (err.message.includes('is not whitelisted')) throw new Error(err.message); throw new Error(ErrorMessage.ERROR_ON_SUBMITTING_TXN); } } @@ -160,16 +214,37 @@ export class Paymaster { const paymasterContract = new ethers.Contract(paymasterAddress, abi, provider); const signer = new Wallet(relayerKey, provider) const balance = await signer.getBalance(); - if (ethers.utils.parseEther(amount.toString()).gte(balance)) + const amountInWei = ethers.utils.parseEther(amount); + if (amountInWei.gte(balance)) throw new Error(`${signer.address} Balance is less than the amount to be deposited`) + const encodedData = paymasterContract.interface.encodeFunctionData('depositFunds', []); - const tx = await signer.sendTransaction({ to: paymasterAddress, data: encodedData, value: ethers.utils.parseEther(amount.toString()) }); + const feeData = await provider.getFeeData(); + let tx: providers.TransactionResponse; + if (!feeData.maxFeePerGas) { + tx = await signer.sendTransaction({ + to: paymasterAddress, + data: encodedData, + value: amountInWei, + gasPrice: feeData.gasPrice ? feeData.gasPrice.add(this.feeMarkUp) : undefined, + }) + } else { + tx = await signer.sendTransaction({ + to: paymasterAddress, + data: encodedData, + value: amountInWei, + maxFeePerGas: feeData.maxFeePerGas ? feeData.maxFeePerGas.add(this.feeMarkUp) : undefined, + maxPriorityFeePerGas: feeData.maxPriorityFeePerGas ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) : undefined, + type: 2, + }); + } // commented the below line to avoid timeouts for long delays in transaction confirmation. // await tx.wait(); return { message: `Successfully deposited with transaction Hash ${tx.hash}` }; - } catch (err) { + } catch (err: any) { + if (err.message.includes('Balance is less than the amount to be deposited')) throw new Error(err.message); throw new Error(ErrorMessage.ERROR_ON_SUBMITTING_TXN); } } diff --git a/backend/src/paymaster/pimlico.ts b/backend/src/paymaster/pimlico.ts index 71eb51c..e1ce5f7 100644 --- a/backend/src/paymaster/pimlico.ts +++ b/backend/src/paymaster/pimlico.ts @@ -16,10 +16,13 @@ export interface ERC20PaymasterBuildOptions { export class PimlicoPaymaster { private contract: Contract; + tokenAddress: Promise; paymasterAddress: string; + constructor(address: string, provider: providers.Provider) { this.paymasterAddress = address; this.contract = new Contract(address, abi, provider) + this.tokenAddress = this.contract.token(); } /** @@ -71,6 +74,20 @@ export class PimlicoPaymaster { ) return paymasterAndData } + + /** + * @dev Generates the paymaster and data for the UserOperation, given token amount + * + * @param userOp the UserOperation to generate the paymasterAndData for (with gas limits already set) + * @param requiredPreFund the required token amount if already calculated + * @returns the paymasterAndData to be filled in + */ + async generatePaymasterAndDataForTokenAmount(userOp: NotPromise, tokenAmount: BigNumber): Promise { + const paymasterAndData = utils.hexlify( + utils.concat([this.contract.address, utils.hexZeroPad(utils.hexlify(tokenAmount), 32)]) + ) + return paymasterAndData + } } async function validatePaymasterOptions( @@ -182,7 +199,7 @@ export async function getERC20Paymaster( nativeAssetOracle: ORACLE_ADDRESS[chainId][NATIVE_ASSET[chainId]], tokenAddress: TOKEN_ADDRESS[chainId][erc20], tokenOracle: ORACLE_ADDRESS[chainId][erc20], - owner: "0x4337000c2828f5260d8921fd25829f606b9e8680" // pimlico address + owner: "0x4337000c2828F5260d8921fD25829F606b9E8680" // pimlico address } } else { parsedOptions = await validatePaymasterOptions(provider, erc20, options) diff --git a/backend/src/plugins/config.ts b/backend/src/plugins/config.ts index 2cac84e..b783fa5 100644 --- a/backend/src/plugins/config.ts +++ b/backend/src/plugins/config.ts @@ -18,6 +18,7 @@ const ConfigSchema = Type.Strict( API_PORT: Type.String(), SUPPORTED_NETWORKS: Type.String() || undefined, ADMIN_WALLET_ADDRESS: Type.String() || undefined, + FEE_MARKUP: Type.String() || '0', }) ); @@ -47,6 +48,7 @@ const configPlugin: FastifyPluginAsync = async (server) => { API_HOST: process.env.API_HOST ?? '', SUPPORTED_NETWORKS: process.env.SUPPORTED_NETWORKS ?? '', ADMIN_WALLET_ADDRESS: process.env.ADMIN_WALLET_ADDRESS ?? '0x80a1874E1046B1cc5deFdf4D3153838B72fF94Ac', + FEE_MARKUP: process.env.FEE_MARKUP ?? '10', } server.decorate("config", config); diff --git a/backend/src/routes/index.ts b/backend/src/routes/index.ts index b7f503f..4847e3f 100644 --- a/backend/src/routes/index.ts +++ b/backend/src/routes/index.ts @@ -3,26 +3,17 @@ import { Type } from "@sinclair/typebox"; import { FastifyPluginAsync } from "fastify"; import { Wallet, ethers, providers } from "ethers"; import { gql, request as GLRequest } from "graphql-request"; +import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager"; import { Paymaster } from "../paymaster/index.js"; import SupportedNetworks from "../../config.json" assert { type: "json" }; -import { TOKEN_ADDRESS } from "../constants/Pimlico.js"; +import { PAYMASTER_ADDRESS } from "../constants/Pimlico.js"; import ErrorMessage from "../constants/ErrorMessage.js"; import ReturnCode from "../constants/ReturnCode.js"; -import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager"; import { decode } from "../utils/crypto.js"; -import { printRequest } from "../utils/common.js"; - -export function getNetworkConfig(key: any, supportedNetworks: any) { - if (supportedNetworks !== '') { - const buffer = Buffer.from(supportedNetworks, 'base64'); - const SUPPORTED_NETWORKS = JSON.parse(buffer.toString()) - return SUPPORTED_NETWORKS.find((chain: any) => { return chain["chainId"] == key }); - } else - return SupportedNetworks.find((chain) => chain.chainId == key); -} +import { printRequest, getNetworkConfig, getSQLdata } from "../utils/common.js"; const routes: FastifyPluginAsync = async (server) => { - const paymaster = new Paymaster(); + const paymaster = new Paymaster(server.config.FEE_MARKUP); const prefixSecretId = 'arka_'; @@ -98,7 +89,7 @@ const routes: FastifyPluginAsync = async (server) => { txnMode = secrets['TRANSACTION_LIMIT'] ?? 0; indexerEndpoint = secrets['INDEXER_ENDPOINT'] ?? process.env.DEFAULT_INDEXER_ENDPOINT; } else { - const record: any = await getSQLdata(api_key); + const record: any = await getSQLdata(api_key, server.sqlite.db, server.log); if (!record) { server.log.info("Invalid Api Key provided") return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) @@ -129,7 +120,7 @@ const routes: FastifyPluginAsync = async (server) => { } if ( mode.toLowerCase() == 'erc20' && - !(TOKEN_ADDRESS[chainId] && TOKEN_ADDRESS[chainId][gasToken]) && + !(PAYMASTER_ADDRESS[chainId] && PAYMASTER_ADDRESS[chainId][gasToken]) && !(customPaymasters[chainId] && customPaymasters[chainId][gasToken]) ) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK_TOKEN }) const networkConfig = getNetworkConfig(chainId, supportedNetworks ?? ''); @@ -163,7 +154,10 @@ const routes: FastifyPluginAsync = async (server) => { break; } case 'erc20': { - result = await paymaster.pimlico(userOp, gasToken, networkConfig.bundler, entryPoint, customPaymasters[chainId] ? customPaymasters[chainId][gasToken] : null); + let paymasterAddress: string; + if (customPaymasters[chainId] && customPaymasters[chainId][gasToken]) paymasterAddress = customPaymasters[chainId][gasToken]; + else paymasterAddress = PAYMASTER_ADDRESS[chainId][gasToken] + result = await paymaster.pimlico(userOp, networkConfig.bundler, entryPoint, paymasterAddress); break; } case 'default': { @@ -216,8 +210,7 @@ const routes: FastifyPluginAsync = async (server) => { privateKey = secrets['PRIVATE_KEY']; supportedNetworks = secrets['SUPPORTED_NETWORKS']; } else { - const record: any = await getSQLdata(api_key); - console.log(record); + const record: any = await getSQLdata(api_key, server.sqlite.db, server.log); if (!record) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) if (record['ERC20_PAYMASTERS']) { const buffer = Buffer.from(record['ERC20_PAYMASTERS'], 'base64'); @@ -243,8 +236,8 @@ const routes: FastifyPluginAsync = async (server) => { let result; if (customPaymasters[chainId] && customPaymasters[chainId][gasToken]) result = { message: customPaymasters[chainId][gasToken] } else { - if (!(TOKEN_ADDRESS[chainId] && TOKEN_ADDRESS[chainId][gasToken])) return reply.code(ReturnCode.FAILURE).send({ error: "Invalid network/token" }) - result = await paymaster.pimlicoAddress(gasToken, networkConfig.bundler, entryPoint); + if (!(PAYMASTER_ADDRESS[chainId] && PAYMASTER_ADDRESS[chainId][gasToken])) return reply.code(ReturnCode.FAILURE).send({ error: "Invalid network/token" }) + result = { message: PAYMASTER_ADDRESS[chainId][gasToken] } } server.log.info(result, 'Response sent: '); if (body.jsonrpc) @@ -263,7 +256,7 @@ const routes: FastifyPluginAsync = async (server) => { "/whitelist", async function (request, reply) { try { - printRequest("/whiteList",request, server.log); + printRequest("/whitelist", request, server.log); const body: any = request.body; const query: any = request.query; const address = body.params[0]; @@ -284,7 +277,7 @@ const routes: FastifyPluginAsync = async (server) => { privateKey = secrets['PRIVATE_KEY']; supportedNetworks = secrets['SUPPORTED_NETWORKS']; } else { - const record: any = await getSQLdata(api_key); + const record: any = await getSQLdata(api_key, server.sqlite.db, server.log); if (!record) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) privateKey = decode(record['PRIVATE_KEY']); supportedNetworks = record['SUPPORTED_NETWORKS']; @@ -321,6 +314,7 @@ const routes: FastifyPluginAsync = async (server) => { server.post("/removeWhitelist", async function (request, reply) { try { + printRequest("/removeWhitelist", request, server.log); const body: any = request.body; const query: any = request.query; const address = body.params[0]; @@ -341,8 +335,7 @@ const routes: FastifyPluginAsync = async (server) => { privateKey = secrets['PRIVATE_KEY']; supportedNetworks = secrets['SUPPORTED_NETWORKS']; } else { - const record: any = await getSQLdata(api_key); - console.log(record); + const record: any = await getSQLdata(api_key, server.sqlite.db, server.log); if (!record) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) privateKey = decode(record['PRIVATE_KEY']); supportedNetworks = record['SUPPORTED_NETWORKS']; @@ -379,12 +372,12 @@ const routes: FastifyPluginAsync = async (server) => { "/checkWhitelist", async function (request, reply) { try { - printRequest("/checkWhiteList", request, server.log); + printRequest("/checkWhitelist", request, server.log); const body: any = request.body; const query: any = request.query; const accountAddress = body.params[0]; - const chainId = query['chainId'] ?? body.params[2]; - const api_key = query['apiKey'] ?? body.params[3]; + const chainId = query['chainId'] ?? body.params[1]; + const api_key = query['apiKey'] ?? body.params[2]; if (!api_key) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) let privateKey = ''; @@ -400,7 +393,7 @@ const routes: FastifyPluginAsync = async (server) => { privateKey = secrets['PRIVATE_KEY']; supportedNetworks = secrets['SUPPORTED_NETWORKS']; } else { - const record: any = await getSQLdata(api_key); + const record: any = await getSQLdata(api_key, server.sqlite.db, server.log); if (!record) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) privateKey = decode(record['PRIVATE_KEY']); supportedNetworks = record['SUPPORTED_NETWORKS']; @@ -459,7 +452,7 @@ const routes: FastifyPluginAsync = async (server) => { privateKey = secrets['PRIVATE_KEY']; supportedNetworks = secrets['SUPPORTED_NETWORKS']; } else { - const record: any = await getSQLdata(api_key); + const record: any = await getSQLdata(api_key, server.sqlite.db, server.log); if (!record) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) privateKey = decode(record['PRIVATE_KEY']); supportedNetworks = record['SUPPORTED_NETWORKS']; @@ -486,21 +479,6 @@ const routes: FastifyPluginAsync = async (server) => { } ) - async function getSQLdata(apiKey: string) { - try { - const result: any[] = await new Promise((resolve, reject) => { - server.sqlite.db.get("SELECT * FROM api_keys WHERE API_KEY = ?", [apiKey], (err: any, rows: any[]) => { - if (err) reject(err); - resolve(rows); - }) - }) - return result; - } catch (err) { - server.log.error(err); - return null; - } - } - async function getIndexerData(sponsor: string, sender: string, month: number, year: number, noOfTxns: number, endpoint: string): Promise { try { const query = gql` diff --git a/backend/src/routes/metadata.ts b/backend/src/routes/metadata.ts new file mode 100644 index 0000000..6e910f2 --- /dev/null +++ b/backend/src/routes/metadata.ts @@ -0,0 +1,108 @@ +import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager"; +import { FastifyPluginAsync } from "fastify"; +import { Wallet, providers } from "ethers"; +import SupportedNetworks from "../../config.json" assert { type: "json" }; +import { getNetworkConfig, printRequest, getSQLdata } from "../utils/common.js"; +import ReturnCode from "../constants/ReturnCode.js"; +import ErrorMessage from "../constants/ErrorMessage.js"; +import { decode } from "../utils/crypto.js"; +import { PAYMASTER_ADDRESS } from "../constants/Pimlico.js"; + + +const metadataRoutes: FastifyPluginAsync = async (server) => { + + const prefixSecretId = 'arka_'; + + let client: SecretsManagerClient; + + const unsafeMode: boolean = process.env.UNSAFE_MODE == "true" ? true : false; + + if (!unsafeMode) { + client = new SecretsManagerClient(); + } + + server.get('/metadata', async function (request, reply) { + try { + printRequest('/metadata', request, server.log); + const query: any = request.query; + const chainId = query['chainId'] ?? 1; + const api_key = query['apiKey']; + + if (!api_key) + return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) + if (!chainId) + return reply.code(ReturnCode.FAILURE).send({error: ErrorMessage.INVALID_DATA}) + let customPaymasters = []; + let privateKey = ''; + let supportedNetworks; + if (!unsafeMode) { + const AWSresponse = await client.send( + new GetSecretValueCommand({ + SecretId: prefixSecretId + api_key, + }) + ); + const secrets = JSON.parse(AWSresponse.SecretString ?? '{}'); + if (!secrets['PRIVATE_KEY']) { + server.log.info("Invalid Api Key provided") + return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) + } + if (secrets['ERC20_PAYMASTERS']) { + const buffer = Buffer.from(secrets['ERC20_PAYMASTERS'], 'base64'); + customPaymasters = JSON.parse(buffer.toString()); + } + privateKey = secrets['PRIVATE_KEY']; + supportedNetworks = secrets['SUPPORTED_NETWORKS']; + } else { + const record: any = await getSQLdata(api_key, server.sqlite.db, server.log); + if (!record) { + server.log.info("Invalid Api Key provided") + return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) + } + if (record['ERC20_PAYMASTERS']) { + const buffer = Buffer.from(record['ERC20_PAYMASTERS'], 'base64'); + customPaymasters = JSON.parse(buffer.toString()); + } + privateKey = decode(record['PRIVATE_KEY']); + supportedNetworks = record['SUPPORTED_NETWORKS']; + } + if (server.config.SUPPORTED_NETWORKS == '' && !SupportedNetworks) { + return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + } + const networkConfig = getNetworkConfig(chainId, supportedNetworks ?? ''); + if (!networkConfig) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + const provider = new providers.JsonRpcProvider(networkConfig.bundler); + const signer = new Wallet(privateKey, provider) + const balance = await signer.getBalance(); + const address = await signer.getAddress(); + const chainsSupported: number[] = []; + if (supportedNetworks) { + const buffer = Buffer.from(supportedNetworks, 'base64'); + const SUPPORTED_NETWORKS = JSON.parse(buffer.toString()) + SUPPORTED_NETWORKS.map((element: { chainId: number; }) => { + chainsSupported.push(element.chainId); + }) + } else { + SupportedNetworks.map(element => { + chainsSupported.push(element.chainId); + }) + } + const tokenPaymasterAddresses = { + ...PAYMASTER_ADDRESS, + ...customPaymasters, + } + return reply.code(ReturnCode.SUCCESS).send({ + sponsorAddress: address, + sponsorWalletBalance: balance, + chainsSupported: chainsSupported, + tokenPaymasters: tokenPaymasterAddresses, + }) + } catch (err: any) { + request.log.error(err); + if (err.name == "ResourceNotFoundException") + return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }); + return reply.code(ReturnCode.FAILURE).send({ error: err.message ?? ErrorMessage.FAILED_TO_PROCESS }); + } + }) +} + +export default metadataRoutes; diff --git a/backend/src/server.ts b/backend/src/server.ts index 1627359..f07cfc2 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -6,11 +6,13 @@ import { providers, ethers } from 'ethers'; import fetch from 'node-fetch'; import database from './plugins/db.js'; import config from './plugins/config.js'; -import routes, { getNetworkConfig } from './routes/index.js'; +import routes from './routes/index.js'; import adminRoutes from './routes/admin.js'; +import metadataRoutes from './routes/metadata.js'; import EtherspotChainlinkOracleAbi from './abi/EtherspotChainlinkOracleAbi.js'; import PimlicoAbi from './abi/PimlicoAbi.js'; import PythOracleAbi from './abi/PythOracleAbi.js'; +import { getNetworkConfig } from './utils/common.js'; let server: FastifyInstance; @@ -40,6 +42,8 @@ const initializeServer = async (): Promise => { await server.register(adminRoutes); + await server.register(metadataRoutes); + // Database await server.register(database); diff --git a/backend/src/utils/common.ts b/backend/src/utils/common.ts index 9cf0915..383ff8e 100644 --- a/backend/src/utils/common.ts +++ b/backend/src/utils/common.ts @@ -1,7 +1,34 @@ import { FastifyBaseLogger, FastifyRequest } from "fastify"; +import SupportedNetworks from "../../config.json" assert { type: "json" }; +import { Database } from "sqlite3"; export function printRequest(methodName: string, request: FastifyRequest, log: FastifyBaseLogger) { log.info(methodName, "called: "); log.info(request.query, "query passed: "); log.info(request.body, "body passed: "); } + +export function getNetworkConfig(key: any, supportedNetworks: any) { + if (supportedNetworks !== '') { + const buffer = Buffer.from(supportedNetworks, 'base64'); + const SUPPORTED_NETWORKS = JSON.parse(buffer.toString()) + return SUPPORTED_NETWORKS.find((chain: any) => { return chain["chainId"] == key }); + } else + return SupportedNetworks.find((chain) => chain.chainId == key); +} + +export async function getSQLdata(apiKey: string, db: Database, log: FastifyBaseLogger) { + try { + const result: any[] = await new Promise((resolve, reject) => { + db.get("SELECT * FROM api_keys WHERE API_KEY = ?", [apiKey], (err: any, rows: any[]) => { + if (err) reject(err); + resolve(rows); + }) + }) + return result; + } catch (err) { + log.error(err); + return null; + } +} + diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d7bc01d..8a47002 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "arka_frontend", - "version": "1.0.3", + "version": "1.1.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "arka_frontend", - "version": "1.0.3", + "version": "1.1.6", "dependencies": { "@babel/plugin-proposal-private-property-in-object": "7.21.11", "@emotion/react": "^11.11.1", diff --git a/frontend/package.json b/frontend/package.json index 6dcdc9f..d78c700 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "arka_frontend", - "version": "1.1.5", + "version": "1.1.6", "private": true, "dependencies": { "@babel/plugin-proposal-private-property-in-object": "7.21.11",