From 6f6116b92e5dcab37d44b53a263739a575e06c40 Mon Sep 17 00:00:00 2001 From: Jineshdarjee Date: Thu, 13 Jun 2024 13:05:05 +0530 Subject: [PATCH 1/4] Added unit test case for epv07 --- backend/config.json.default | 292 ---------- backend/demo.env | 16 - backend/jest.config.js | 48 +- backend/package.json | 2 +- backend/src/paymaster/index.test.ts | 733 ++++++++++++++++++-------- backend/src/paymaster/index.ts | 576 ++++++++++++++------ backend/src/paymaster/pimlico.test.ts | 409 +++++++++----- backend/src/utils/common.ts | 98 ++-- backend/tsconfig.json | 2 +- 9 files changed, 1298 insertions(+), 878 deletions(-) delete mode 100644 backend/config.json.default delete mode 100644 backend/demo.env diff --git a/backend/config.json.default b/backend/config.json.default deleted file mode 100644 index d8ae092..0000000 --- a/backend/config.json.default +++ /dev/null @@ -1,292 +0,0 @@ -[ - { - "chainId": 1, - "bundler": "https://ethereum-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x7F690e93CecFca5A31E6e1dF50A33F6d3059048c" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 10, - "bundler": "https://optimism-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0x805650ce74561C85baA44a8Bd13E19633Fd0F79d" - }, - "thresholdValue": "21.8", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 14, - "bundler": "https://flare-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0x8A41594e5c6Fe492e437414c24eA6f401186b8d2" - }, - "thresholdValue": "1556", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 30, - "bundler": "https://rootstock-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26dD53b325bFFaACdFA224692EFF4C448C4" - }, - "thresholdValue": "0.00079", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 31, - "bundler": "https://testnet-rpc.etherspot.io/v1/31", - "contracts": { - "etherspotPaymasterAddress": "0xD302BE6e9D3fE0fBf8122a0C34611E31c0D0E792" - }, - "thresholdValue": "0.00079", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 56, - "bundler": "https://bnb-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0xEA5ecE95D3A28f9faB161779d20128b449F9EC9C" - }, - "thresholdValue": "0.09", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 97, - "bundler": "https://testnet-rpc.etherspot.io/v1/97", - "contracts": { - "etherspotPaymasterAddress": "0x153e26707DF3787183945B88121E4Eb188FDCAAA" - }, - "thresholdValue": "0.09", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 100, - "bundler": "https://gnosis-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x373aBcF1EA9e5802778E32870e7f72C8A6a90349" - }, - "thresholdValue": "50", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 114, - "bundler": "https://testnet-rpc.etherspot.io/v1/114", - "contracts": { - "etherspotPaymasterAddress": "0x2a18C360b525824B3e5656B5a705554f2a5036Be" - }, - "thresholdValue": "1556", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 122, - "bundler": "https://fuse-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0xEC2EE24E79C73DB13Dd9bC782856a5296626b7eb" - }, - "thresholdValue": "669", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 123, - "bundler": "https://testnet-rpc.etherspot.io/v1/123", - "contracts": { - "etherspotPaymasterAddress": "0xAF628C207513c5E51d894b3733056B8080634923" - }, - "thresholdValue": "669", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 137, - "bundler": "https://polygon-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0x26FeC24b0D467C9de105217B483931e8f944ff50" - }, - "thresholdValue": "69.85", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 5000, - "bundler": "https://mantle-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x8A41594e5c6Fe492e437414c24eA6f401186b8d2" - }, - "thresholdValue": "44.24", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 5003, - "bundler": "https://testnet-rpc.etherspot.io/v1/5003", - "contracts": { - "etherspotPaymasterAddress": "0x8350355c08aDAC387b443782124A30A8942BeC2e" - }, - "thresholdValue": "44.24", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 8217, - "bundler": "https://klaytn-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x4ebd86AAF89151b5303DB072e0205C668e31E5E7" - }, - "thresholdValue": "275.2", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 8453, - "bundler": "https://base-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" - }, - "thresholdValue": "15.19", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 42161, - "bundler": "https://arbitrum-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0xEC2EE24E79C73DB13Dd9bC782856a5296626b7eb" - }, - "thresholdValue": "43.10", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 43114, - "bundler": "https://avalanche-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x527569794781671319f20374A050BDbef4181aB3" - }, - "thresholdValue": "1.4", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 59144, - "bundler": "https://linea-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 84532, - "bundler": "https://testnet-rpc.etherspot.io/v1/84532", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" - }, - "thresholdValue": "15.19", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 421614, - "bundler": "https://testnet-rpc.etherspot.io/v1/421614", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" - }, - "thresholdValue": "43.10", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 534351, - "bundler": "https://testnet-rpc.etherspot.io/v1/534351", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 534352, - "bundler": "https://scroll-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 11155111, - "bundler": "https://testnet-rpc.etherspot.io/v1/11155111", - "contracts": { - "etherspotPaymasterAddress": "0xcaDBADcFeD5530A49762DFc9d1d712CcD6b09b25" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 28122024, - "bundler": "https://testnet-rpc.etherspot.io/v1/28122024", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "orochi", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 11155420, - "bundler": "https://testnet-rpc.etherspot.io/v1/11155420", - "contracts": { - "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" - }, - "thresholdValue": "21.8", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 888888888, - "bundler": "https://ancient8-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "orochi", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 80002, - "bundler": "https://testnet-rpc.etherspot.io/v1/80002", - "contracts": { - "etherspotPaymasterAddress": "0xe893a26dd53b325bffaacdfa224692eff4c448c4" - }, - "thresholdValue": "0.01", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 80002, - "bundler": "https://testnet-rpc.etherspot.io/v2/80002", - "contracts": { - "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" - }, - "thresholdValue": "0.01", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x0000000071727De22E5E9d8BAf0edAc6f37da032" - } -] diff --git a/backend/demo.env b/backend/demo.env deleted file mode 100644 index f78986c..0000000 --- a/backend/demo.env +++ /dev/null @@ -1,16 +0,0 @@ -NODE_ENV=development -LOG_LEVEL=debug -UNSAFE_MODE=false - -API_HOST=127.0.0.1 -API_PORT=5050 - -STACKUP_API_KEY= -SUPPORTED_NETWORKS= -ADMIN_WALLET_ADDRESS= -DEFAULT_INDEXER_ENDPOINT=http://localhost:3003 -FEE_MARKUP= -MULTI_TOKEN_MARKUP=1150000 -ETHERSCAN_GAS_ORACLES= -DEFAULT_API_KEY= -WEBHOOK_URL= diff --git a/backend/jest.config.js b/backend/jest.config.js index 9200cd9..c409215 100644 --- a/backend/jest.config.js +++ b/backend/jest.config.js @@ -1,39 +1,33 @@ /** @type {import('ts-jest').JestConfigWithTsJest} */ export default { - preset: 'ts-jest/presets/js-with-ts-esm', + preset: "ts-jest/presets/js-with-ts-esm", moduleNameMapper: { - '^(\\.{1,2}/.*)\\.js$': '$1', + "^(\\.{1,2}/.*)\\.js$": "$1", }, - testEnvironment: 'node', + testEnvironment: "node", transform: { - '^.+\\.ts?$': [ - 'ts-jest', - { - useESM: true, - }, - ], + "^.+\\.ts?$": [ + "ts-jest", + { + useESM: true, + }, + ], }, transformIgnorePatterns: [ - 'node_modules/(?!(data-uri-to-buffer|formdata-polyfill|fetch-blob|node-fetch)/)', - ], - testPathIgnorePatterns: [ - '/node_modules/', - '/build/' + "node_modules/(?!(data-uri-to-buffer|formdata-polyfill|fetch-blob|node-fetch)/)", ], + testPathIgnorePatterns: ["/node_modules/", "/build/"], resetModules: true, - testTimeout: 30000, + testTimeout: 90000, coverageThreshold: { - global: { - statements: 95, - branches: 75, - functions: 100, - lines: 95, - }, + global: { + statements: 95, + branches: 75, + functions: 100, + lines: 95, + }, }, - coveragePathIgnorePatterns: [ - 'src/server.ts', - 'src/plugins/config.ts', - ], + coveragePathIgnorePatterns: ["src/server.ts", "src/plugins/config.ts"], collectCoverage: true, - coverageReporters: ["lcov", "text"] -} \ No newline at end of file + coverageReporters: ["lcov", "text"], +}; diff --git a/backend/package.json b/backend/package.json index 9c920e9..96e7bd1 100644 --- a/backend/package.json +++ b/backend/package.json @@ -60,7 +60,7 @@ "eslint": "8.28.0", "eslint-config-prettier": "8.5.0", "eslint-plugin-prettier": "4.2.1", - "jest": "29.6.2", + "jest": "29.7", "pino-pretty": "8.1.0", "prettier": "2.8.0", "ts-jest": "29.1.1", diff --git a/backend/src/paymaster/index.test.ts b/backend/src/paymaster/index.test.ts index 5b26a9a..44dd954 100644 --- a/backend/src/paymaster/index.test.ts +++ b/backend/src/paymaster/index.test.ts @@ -3,319 +3,594 @@ 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('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', - initCode: '0x', - callData: '0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000', - callGasLimit: '0x88b8', - verificationGasLimit: '0x186a0', - maxFeePerGas: '0x6fc23ac10', - maxPriorityFeePerGas: '0x6fc23ac00', - paymasterAndData: '0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', - signature: '0x', - preVerificationGas: '0xc6c4' +describe("Validate the Arka Paymaster on Sepolia", () => { + const paymaster = new Paymaster("0", "1150000"); + const relayerKey = + "0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb2"; // Testing wallet private key only has Mumbai funds in it + const chainId = 80002; + + const paymasterAddressV06 = "0xe893a26dd53b325bffaacdfa224692eff4c448c4"; + const paymasterAddressV07 = "0x810FA4C915015b703db0878CF2B9344bEB254a40"; + const entryPointAddressV06 = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; + const entryPointAddressV07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032"; + const entryPointAddressPimlico = "0xcaDBADcFeD5530A49762DFc9d1d712CcD6b09b25"; + const bundlerUrlV06 = "https://testnet-rpc.etherspot.io/v1/80002"; + const bundlerUrlV07 = "https://testnet-rpc.etherspot.io/v2/80002"; + const bundlerUrlPimlico = "https://testnet-rpc.etherspot.io/v1/11155111"; + const providerV06 = new providers.JsonRpcProvider(bundlerUrlV06); + const providerV07 = new providers.JsonRpcProvider(bundlerUrlV07); + const signerV06 = new Wallet(relayerKey, providerV06); + const signerV07 = new Wallet(relayerKey, providerV07); + + const userOpV06 = { + sender: "0x1434E767F0D878de8C053896ec6F7e5d1951eE00", + nonce: "0x0", + initCode: + "0x7f6d8f107fe8551160bd5351d5f1514a6ad5d40e5fbfb9cf0000000000000000000000009ae4935fae629dd042c18df520322e0e9efad73d0000000000000000000000000000000000000000000000000000000000000000", + callData: + "0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000009184e72a000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", + callGasLimit: "0xc7ed", + verificationGasLimit: "0x4d62f", + maxFeePerGas: "0x59682f1e", + maxPriorityFeePerGas: "0x59682f00", + paymasterAndData: "0x", + preVerificationGas: "0xb1f4", + signature: + "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c", }; - test('SMOKE: validate the sign function with valid details', async () => { - const Mock_Valid_Until = '0x00000000deadbeef'; // max value - const Mock_Valid_After = '0x0000000000001234'; // min value + const userOpV07 = { + sender: "0x4040fC64C54FFD875F635D16ff2807a619AeFd69", + nonce: "0x4", + callData: + "0x541d63c800000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac00000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + callGasLimit: "0x0", + verificationGasLimit: "0x0", + preVerificationGas: "0x0", + maxFeePerGas: "0x85e0abb614", + maxPriorityFeePerGas: "0x85e0abb600", + signature: + "0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + }; + + test("SMOKE: validate the signV06 function with valid details", async () => { + 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, signer); + const signResponse = await paymaster.signV06( + userOpV06, + Mock_Valid_Until, + Mock_Valid_After, + entryPointAddressV06, + paymasterAddressV06, + bundlerUrlV06, + signerV06, + true + ); + try { - expect(signResponse).toHaveProperty('paymasterAndData'); + expect(signResponse).toHaveProperty("paymasterAndData"); } catch (e) { - fail("The paymasterAndData details is not displayed in the sign response") + throw new Error( + "The paymasterAndData details is not displayed in the signV06 response" + ); } try { - expect(signResponse).toHaveProperty('verificationGasLimit'); + expect(signResponse).toHaveProperty("verificationGasLimit"); } catch (e) { - fail("The verificationGasLimit details is not displayed in the sign response") + throw new Error( + "The verificationGasLimit details is not displayed in the signV06 response" + ); } try { - expect(signResponse).toHaveProperty('preVerificationGas'); + expect(signResponse).toHaveProperty("preVerificationGas"); } catch (e) { - fail("The preVerificationGas details is not displayed in the sign response") + throw new Error( + "The preVerificationGas details is not displayed in the signV06 response" + ); } try { - expect(signResponse).toHaveProperty('callGasLimit'); + expect(signResponse).toHaveProperty("callGasLimit"); } catch (e) { - fail("The callGasLimit details is not displayed in the sign response") + throw new Error( + "The callGasLimit details is not displayed in the signV06 response" + ); } } catch (e) { - fail('An error is displayed while performing sign action.') + throw new Error("An error is displayed while performing sign action."); } }); - test('SMOKE: validate the pimlico function with valid details', async () => { - const gasToken = 'USDC'; + test("SMOKE: validate the signV07 function with valid details", async () => { + const Mock_Valid_Until = "0x00000000deadbeef"; // max value + const Mock_Valid_After = "0x0000000000001234"; // min value try { - const tokenPaymasterAddress = PAYMASTER_ADDRESS[chainId][gasToken]; - const pimlicoResponse = await paymaster.pimlico(userOp, bundlerUrl, entryPointAddress, tokenPaymasterAddress); + const signResponse = await paymaster.signV07( + userOpV07, + Mock_Valid_Until, + Mock_Valid_After, + entryPointAddressV07, + paymasterAddressV07, + bundlerUrlV07, + signerV07, + true + ); try { - expect(pimlicoResponse).toHaveProperty('paymasterAndData'); + expect(signResponse).toHaveProperty("paymaster"); } catch (e) { - fail("The paymasterAndData details is not displayed in the pimlico response") + throw new Error( + "The paymaster details is not displayed in the signV07 response" + ); } try { - expect(pimlicoResponse).toHaveProperty('verificationGasLimit'); + expect(signResponse).toHaveProperty("paymasterData"); } catch (e) { - fail("The verificationGasLimit details is not displayed in the pimlico response") + throw new Error( + "The paymasterData details is not displayed in the signV07 response" + ); } try { - expect(pimlicoResponse).toHaveProperty('preVerificationGas'); + expect(signResponse).toHaveProperty("verificationGasLimit"); } catch (e) { - fail("The preVerificationGas details is not displayed in the pimlico response") + throw new Error( + "The verificationGasLimit details is not displayed in the signV07 response" + ); } try { - expect(pimlicoResponse).toHaveProperty('callGasLimit'); + expect(signResponse).toHaveProperty("preVerificationGas"); } catch (e) { - fail("The callGasLimit details is not displayed in the pimlico response") + throw new Error( + "The preVerificationGas details is not displayed in the signV07 response" + ); } - } catch (e) { - fail('An error is displayed while using the pimlico function.') - } - }) - - test('SMOKE: validate the pimlicoAddress function with valid details', async () => { - const gasToken = 'USDC'; - try { - const pimlicoAddressResponse = await paymaster.pimlicoAddress(gasToken, chainId); - try { - expect(pimlicoAddressResponse).toHaveProperty('message'); + expect(signResponse).toHaveProperty("callGasLimit"); } catch (e) { - fail("The message details is not displayed in the pimlico address response") + throw new Error( + "The callGasLimit details is not displayed in the signV07 response" + ); } - } catch (e) { - fail('An error is displayed while using the pimlicoAddress function.') - } - }) - - test('SMOKE: validate the deposit function with valid details', async () => { - const amount = '0.0000001' - try { - const depositResponse = await paymaster.deposit(amount, paymasterAddress, bundlerUrl, relayerKey, chainId); - - const expectedMessage = depositResponse.message; - const actualMessage = 'Successfully deposited with transaction Hash'; - - if (expectedMessage.includes(actualMessage)) { - console.log('The deposit function is working as expected.') - } else { - fail('The valid message is not displayed while performing the deposit action.') + try { + expect(signResponse).toHaveProperty("paymasterVerificationGasLimit"); + } catch (e) { + throw new Error( + "The paymasterVerificationGasLimit details is not displayed in the signV07 response" + ); } - } catch (e: any) { - fail('An error is displayed while performing the deposit action.') - } - }) - - test('REGRESSION: validate the sign function with invalid sender address detail', async () => { - const userOp = { - sender: '0x7b3078b9A28DF76453CDfD2bA5E75f32f067632', // invalid sender address - nonce: '0x1', - initCode: '0x', - callData: '0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000', - callGasLimit: '0x88b8', - verificationGasLimit: '0x186a0', - maxFeePerGas: '0x6fc23ac10', - maxPriorityFeePerGas: '0x6fc23ac00', - paymasterAndData: '0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', - signature: '0x0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', - preVerificationGas: '0xc6c4' - }; - - const Mock_Valid_Until = '0x00000000deadbeef'; - const Mock_Valid_After = '0x0000000000001234'; - try { - 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 = '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.') - } else { - fail('The respective validation is not displayed for invalid sender address while using the sign function.') + try { + expect(signResponse).toHaveProperty("paymasterPostOpGasLimit"); + } catch (e) { + throw new Error( + "The paymasterPostOpGasLimit details is not displayed in the signV07 response" + ); } + } catch (e) { + throw new Error("An error is displayed while performing signV07 action."); } - }); - test('REGRESSION: validate the pimlico function with invalid custom paymaster address', async () => { - const gasToken = 'USDC'; - const address = ethers.Wallet.createRandom(); // random address + test.skip("SMOKE: validate the pimlico function with valid details", async () => { + const chainId = "11155111"; + const gasToken = "USDC"; try { - 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 = '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.') - } else { - fail('The respective validation is not displayed for invalid customPaymasterAddress while using the pimlico function.') - } - } - }) - - test('REGRESSION: validate the pimlico function with invalid sender address', async () => { - const gasToken = 'USDC'; - const userOp = { - sender: '0x7b3078b9A28DF76453CDfD2bA5E75f32f067632', // invalid address - nonce: '0x1', - initCode: '0x', - callData: '0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000', - callGasLimit: '0x88b8', - verificationGasLimit: '0x186a0', - maxFeePerGas: '0x6fc23ac10', - maxPriorityFeePerGas: '0x6fc23ac00', - paymasterAndData: '0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', - signature: '0x', - preVerificationGas: '0xc6c4' - }; + const tokenPaymasterAddress = PAYMASTER_ADDRESS[chainId][gasToken]; + const pimlicoResponse = await paymaster.pimlico( + userOpV06, + bundlerUrlPimlico, + entryPointAddressPimlico, + tokenPaymasterAddress + ); - try { - 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 = ' 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.') - } else { - fail('The respective validation is not displayed for invalid sender address while using the pimlico function.') + try { + expect(pimlicoResponse).toHaveProperty("paymasterAndData"); + } catch (e) { + throw new Error( + "The paymasterAndData details is not displayed in the pimlico response" + ); } - } - }) - test('REGRESSION: validate the whitelistAddresses function with not whitelisted address', async () => { - const wallet = ethers.Wallet.createRandom(); - const address = [wallet.address]; // not whitelisted address - try { - const whitelistAddresses = await paymaster.whitelistAddresses(address, paymasterAddress, bundlerUrl, relayerKey, chainId); + try { + expect(pimlicoResponse).toHaveProperty("verificationGasLimit"); + } catch (e) { + throw new Error( + "The verificationGasLimit details is not displayed in the pimlico response" + ); + } - if (whitelistAddresses.message.includes('Successfully whitelisted with transaction Hash')) { - console.log('The address is whitelisted successfully.') - } else { - fail('The expected success message is not displayed while performing the whitelistAddress action.') + try { + expect(pimlicoResponse).toHaveProperty("preVerificationGas"); + } catch (e) { + throw new Error( + "The preVerificationGas details is not displayed in the pimlico response" + ); } - } catch (e: any) { - fail('An error is displayed while performing the whitelistAddress action.') - } - }) - test('REGRESSION: validate the whitelistAddresses function with already whitelisted address', async () => { - const address = ['0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321']; // already whitelisted address - try { - await paymaster.whitelistAddresses(address, paymasterAddress, bundlerUrl, relayerKey, chainId); - fail('Address is whitelisted, However it was already whitelisted.') - } catch (e: any) { - const actualMessage = 'already whitelisted'; - const expectedMessage = e.message; - if (expectedMessage.includes(actualMessage)) { - console.log('The address is already whitelisted.') - } else { - fail('The respective validation is not displayed for already whitelisted address. ') + try { + expect(pimlicoResponse).toHaveProperty("callGasLimit"); + } catch (e) { + throw new Error( + "The callGasLimit details is not displayed in the pimlico response" + ); } + } catch (e) { + console.log("error:::::::::::::::", e); + throw new Error( + "An error is displayed while using the pimlico function." + ); } - }) + }); - test('REGRESSION: validate the whitelistAddresses function with invalid relayerKey', async () => { - const address = ['0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321']; // already whitelisted address - const relayerKey = '0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb'; // invalid relayerKey + test("SMOKE: validate the pimlicoAddress function with valid details", async () => { + const chainId = 11155111; + const gasToken = "USDC"; try { - await paymaster.whitelistAddresses(address, paymasterAddress, bundlerUrl, relayerKey, chainId); - fail('Address is whitelisted, however the relayerKey is invalid.') - } catch (e: any) { - 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.') - } else { - fail('The respective validation is not displayed for invalid relayerKey while address whitelisting.') + const pimlicoAddressResponse = await paymaster.pimlicoAddress( + gasToken, + chainId + ); + try { + expect(pimlicoAddressResponse).toHaveProperty("message"); + } catch (e) { + throw new Error( + "The message details is not displayed in the pimlico address response" + ); } + } catch (e) { + console.log("error:::::::::", e); + throw new Error( + "An error is displayed while using the pimlicoAddress function." + ); } - }) + }); - test('REGRESSION: validate the checkWhitelistAddress function with whitelisted address', async () => { - const address = '0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321'; // whitelisted address + test.skip("SMOKE: validate the deposit function with valid details", async () => { + const amount = "0.0000001"; try { - const checkWhitelistAddressResponse = await paymaster.checkWhitelistAddress(address, paymasterAddress, bundlerUrl, relayerKey); - if (checkWhitelistAddressResponse === true) { - console.log('The address is whitelisted.') - } else { - fail('The address is displayed not whitelisted, however it is already whitelisted.') - } - } catch (e: any) { - fail('An error is displayed while checking the address for whitelisting.') + const depositResponse = await paymaster.deposit( + amount, + paymasterAddressV07, + bundlerUrlV07, + relayerKey, + chainId + ); - } - }) + const expectedMessage = depositResponse.message; + const actualMessage = "Successfully deposited with transaction Hash"; - test('REGRESSION: validate the checkWhitelistAddress function with non whitelisted address', async () => { - const address = '0x8350355c08aDAC387b443782124A30A8942BeC2e'; // non whitelisted address - try { - const checkWhitelistAddressResponse = await paymaster.checkWhitelistAddress(address, paymasterAddress, bundlerUrl, relayerKey); - if (checkWhitelistAddressResponse === false) { - console.log('The address is not whitelisted as expected.') + if (expectedMessage.includes(actualMessage)) { + console.log("The deposit function is working as expected."); } else { - fail('The address is displayed whitelisted, however it is not whitelisted.') + throw new Error( + "The valid message is not displayed while performing the deposit action." + ); } } catch (e: any) { - fail('An error is displayed while checking the address for whitelisting.') + console.log("error:::::::::::", e); + throw new Error( + "An error is displayed while performing the deposit action." + ); } - }) + }); - test('REGRESSION: validate the checkWhitelistAddress function with invalid relayerKey', async () => { - const address = '0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321'; - const relayerKey = '0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb'; // invalid relayerKey + test("REGRESSION: validate the signV06 function with invalid sender address detail", async () => { + const userOp = { + sender: "0x1434E767F0D878de8C053896ec6F7e5d1951eE0", // invalid sender address + nonce: "0x0", + initCode: + "0x7f6d8f107fe8551160bd5351d5f1514a6ad5d40e5fbfb9cf0000000000000000000000009ae4935fae629dd042c18df520322e0e9efad73d0000000000000000000000000000000000000000000000000000000000000000", + callData: + "0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000009184e72a000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", + callGasLimit: "0xc7ed", + verificationGasLimit: "0x4d62f", + maxFeePerGas: "0x59682f1e", + maxPriorityFeePerGas: "0x59682f00", + paymasterAndData: "0x", + preVerificationGas: "0xb1f4", + signature: + "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c", + }; + + const Mock_Valid_Until = "0x00000000deadbeef"; + const Mock_Valid_After = "0x0000000000001234"; try { - await paymaster.checkWhitelistAddress(address, paymasterAddress, bundlerUrl, relayerKey); - fail('The whitelist address checking is performed, however the relayerKey is invalid.') + await paymaster.signV06( + userOp, + Mock_Valid_Until, + Mock_Valid_After, + entryPointAddressV06, + paymasterAddressV06, + bundlerUrlV06, + signerV06, + true + ); + throw new Error( + "The sign function is worked, however the sender address is invalid." + ); } catch (e: any) { - const actualMessage = 'rpcError while checking whitelist'; + const actualMessage = + "Please contact support team RawErrorMsg:invalid address"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The relayerKey is invalid while checking the whitelist address.') + console.log( + "The sender address is invalid while using the sign function." + ); } else { - fail('The respective validation is not displayed for invalid relayerKey while checking the whitelist address.') + throw new Error( + "The respective validation is not displayed for invalid sender address while using the sign function." + ); } } - }) + }); - test('REGRESSION: validate the deposit function with invalid amount', async () => { - const amount = '10000' // invalid amount + test("REGRESSION: validate the pimlico function with invalid custom paymaster address", async () => { + const gasToken = "USDC"; + const address = ethers.Wallet.createRandom(); // random address try { - await paymaster.deposit(amount, paymasterAddress, bundlerUrl, relayerKey, chainId); - fail('The deposite action is performed with invalid amount.') + await paymaster.pimlico( + userOpV06, + bundlerUrlV06, + entryPointAddressV06, + address.toString() + ); // invalid custom paymaster address + throw new Error( + "The pimlico function is worked, however the customPaymasterAddress is invalid." + ); } catch (e: any) { - const actualMessage = 'Balance is less than the amount to be deposited'; + const actualMessage = + "Please contact support team RawErrorMsg: network does not support ENS"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The amount is invalid while performing the deposit.') + console.log( + "The customPaymasterAddress is invalid while using the pimlico function." + ); } else { - fail('The respective validation is not displayed for invalid amount while deposit.') + throw new Error( + "The respective validation is not displayed for invalid customPaymasterAddress while using the pimlico function." + ); } } - }) -}); \ No newline at end of file + }); + + // test("REGRESSION: validate the pimlico function with invalid sender address", async () => { + // const gasToken = "USDC"; + // const userOp = { + // sender: "0x1434E767F0D878de8C053896ec6F7e5d1951eE0", // invalid sender address + // nonce: "0x0", + // initCode: + // "0x7f6d8f107fe8551160bd5351d5f1514a6ad5d40e5fbfb9cf0000000000000000000000009ae4935fae629dd042c18df520322e0e9efad73d0000000000000000000000000000000000000000000000000000000000000000", + // callData: + // "0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000009184e72a000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", + // callGasLimit: "0xc7ed", + // verificationGasLimit: "0x4d62f", + // maxFeePerGas: "0x59682f1e", + // maxPriorityFeePerGas: "0x59682f00", + // paymasterAndData: "0x", + // preVerificationGas: "0xb1f4", + // signature: + // "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c", + // }; + + // try { + // await paymaster.pimlico( + // userOp, + // bundlerUrlV06, + // entryPointAddressV06, + // PAYMASTER_ADDRESS[chainId][gasToken] + // ); + // throw new Error( + // "The pimlico function is worked, however the sender address is invalid." + // ); + // } catch (e: any) { + // 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." + // ); + // } else { + // throw new Error( + // "The respective validation is not displayed for invalid sender address while using the pimlico function." + // ); + // } + // } + // }); + + // test("REGRESSION: validate the whitelistAddresses function with not whitelisted address", async () => { + // const wallet = ethers.Wallet.createRandom(); + // const address = [wallet.address]; // not whitelisted address + // try { + // const whitelistAddresses = await paymaster.whitelistAddresses( + // address, + // paymasterAddressV06, + // bundlerUrlV06, + // relayerKey, + // chainId + // ); + + // if ( + // whitelistAddresses.message.includes( + // "Successfully whitelisted with transaction Hash" + // ) + // ) { + // console.log("The address is whitelisted successfully."); + // } else { + // throw new Error( + // "The expected success message is not displayed while performing the whitelistAddress action." + // ); + // } + // } catch (e: any) { + // throw new Error( + // "An error is displayed while performing the whitelistAddress action." + // ); + // } + // }); + + // test("REGRESSION: validate the whitelistAddresses function with already whitelisted address", async () => { + // const address = ["0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321"]; // already whitelisted address + // try { + // await paymaster.whitelistAddresses( + // address, + // paymasterAddressV06, + // bundlerUrlV06, + // relayerKey, + // chainId + // ); + // throw new Error( + // "Address is whitelisted, However it was already whitelisted." + // ); + // } catch (e: any) { + // const actualMessage = "already whitelisted"; + // const expectedMessage = e.message; + // if (expectedMessage.includes(actualMessage)) { + // console.log("The address is already whitelisted."); + // } else { + // throw new Error( + // "The respective validation is not displayed for already whitelisted address. " + // ); + // } + // } + // }); + + // test("REGRESSION: validate the whitelistAddresses function with invalid relayerKey", async () => { + // const address = ["0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321"]; // already whitelisted address + // const relayerKey = + // "0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb"; // invalid relayerKey + // try { + // await paymaster.whitelistAddresses( + // address, + // paymasterAddressV06, + // bundlerUrlV06, + // relayerKey, + // chainId + // ); + // throw new Error( + // "Address is whitelisted, however the relayerKey is invalid." + // ); + // } catch (e: any) { + // 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." + // ); + // } else { + // throw new Error( + // "The respective validation is not displayed for invalid relayerKey while address whitelisting." + // ); + // } + // } + // }); + + // test("REGRESSION: validate the checkWhitelistAddress function with whitelisted address", async () => { + // const address = "0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321"; // whitelisted address + // try { + // const checkWhitelistAddressResponse = + // await paymaster.checkWhitelistAddress( + // address, + // paymasterAddressV06, + // bundlerUrlV06, + // relayerKey + // ); + // if (checkWhitelistAddressResponse === true) { + // console.log("The address is whitelisted."); + // } else { + // throw new Error( + // "The address is displayed not whitelisted, however it is already whitelisted." + // ); + // } + // } catch (e: any) { + // throw new Error( + // "An error is displayed while checking the address for whitelisting." + // ); + // } + // }); + + // test("REGRESSION: validate the checkWhitelistAddress function with non whitelisted address", async () => { + // const address = "0x8350355c08aDAC387b443782124A30A8942BeC2e"; // non whitelisted address + // try { + // const checkWhitelistAddressResponse = + // await paymaster.checkWhitelistAddress( + // address, + // paymasterAddressV06, + // bundlerUrlV06, + // relayerKey + // ); + // if (checkWhitelistAddressResponse === false) { + // console.log("The address is not whitelisted as expected."); + // } else { + // throw new Error( + // "The address is displayed whitelisted, however it is not whitelisted." + // ); + // } + // } catch (e: any) { + // throw new Error( + // "An error is displayed while checking the address for whitelisting." + // ); + // } + // }); + + // test("REGRESSION: validate the checkWhitelistAddress function with invalid relayerKey", async () => { + // const address = "0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321"; + // const relayerKey = + // "0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb"; // invalid relayerKey + // try { + // await paymaster.checkWhitelistAddress( + // address, + // paymasterAddressV06, + // bundlerUrlV06, + // relayerKey + // ); + // throw new Error( + // "The whitelist address checking is performed, however the relayerKey is invalid." + // ); + // } catch (e: any) { + // const actualMessage = "rpcError while checking whitelist"; + // const expectedMessage = e.message; + // if (expectedMessage.includes(actualMessage)) { + // console.log( + // "The relayerKey is invalid while checking the whitelist address." + // ); + // } else { + // throw new Error( + // "The respective validation is not displayed for invalid relayerKey while checking the whitelist address." + // ); + // } + // } + // }); + + // test("REGRESSION: validate the deposit function with invalid amount", async () => { + // const amount = "10000"; // invalid amount + // try { + // await paymaster.deposit( + // amount, + // paymasterAddressV06, + // bundlerUrlV06, + // relayerKey, + // chainId + // ); + // throw new Error("The deposite action is performed with invalid amount."); + // } catch (e: any) { + // 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."); + // } else { + // throw new Error( + // "The respective validation is not displayed for invalid amount while deposit." + // ); + // } + // } + // }); +}); diff --git a/backend/src/paymaster/index.ts b/backend/src/paymaster/index.ts index b81933d..7644edf 100644 --- a/backend/src/paymaster/index.ts +++ b/backend/src/paymaster/index.ts @@ -1,40 +1,69 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { providers, Wallet, ethers, Contract, BigNumber, BigNumberish, utils } from 'ethers'; -import { arrayify, BytesLike, defaultAbiCoder, hexConcat, hexZeroPad } from 'ethers/lib/utils.js'; -import { FastifyBaseLogger } from 'fastify'; -import EtherspotAbiV06 from '../abi/EtherspotAbi.js'; +import { + providers, + Wallet, + ethers, + Contract, + BigNumber, + BigNumberish, + utils, +} from "ethers"; +import { + arrayify, + BytesLike, + defaultAbiCoder, + hexConcat, + hexZeroPad, +} from "ethers/lib/utils.js"; +import { FastifyBaseLogger } from "fastify"; +import EtherspotAbiV06 from "../abi/EtherspotAbi.js"; import EtherspotAbiV07 from "../abi/EtherspotVerifyingSignerAbi.js"; -import { PimlicoPaymaster } from './pimlico.js'; -import ErrorMessage from '../constants/ErrorMessage.js'; -import { PAYMASTER_ADDRESS } from '../constants/Pimlico.js'; -import { getEtherscanFee } from '../utils/common.js'; -import MultiTokenPaymasterAbi from '../abi/MultiTokenPaymasterAbi.js'; -import OrochiOracleAbi from '../abi/OrochiOracleAbi.js'; -import ChainlinkOracleAbi from '../abi/ChainlinkOracleAbi.js'; +import { PimlicoPaymaster } from "./pimlico.js"; +import ErrorMessage from "../constants/ErrorMessage.js"; +import { PAYMASTER_ADDRESS } from "../constants/Pimlico.js"; +import { getEtherscanFee } from "../utils/common.js"; +import MultiTokenPaymasterAbi from "../abi/MultiTokenPaymasterAbi.js"; +import OrochiOracleAbi from "../abi/OrochiOracleAbi.js"; +import ChainlinkOracleAbi from "../abi/ChainlinkOracleAbi.js"; export class Paymaster { feeMarkUp: BigNumber; multiTokenMarkUp: Number; constructor(feeMarkUp: string, multiTokenMarkUp: string) { - this.feeMarkUp = ethers.utils.parseUnits(feeMarkUp, 'gwei'); - if (isNaN(Number(multiTokenMarkUp))) this.multiTokenMarkUp = 1150000 // 15% more of the actual cost. Can be anything between 1e6 to 2e6 + this.feeMarkUp = ethers.utils.parseUnits(feeMarkUp, "gwei"); + if (isNaN(Number(multiTokenMarkUp))) + this.multiTokenMarkUp = 1150000; // 15% more of the actual cost. Can be anything between 1e6 to 2e6 else this.multiTokenMarkUp = Number(multiTokenMarkUp); } - packUint (high128: BigNumberish, low128: BigNumberish): string { - return hexZeroPad(BigNumber.from(high128).shl(128).add(low128).toHexString(), 32) + packUint(high128: BigNumberish, low128: BigNumberish): string { + return hexZeroPad( + BigNumber.from(high128).shl(128).add(low128).toHexString(), + 32 + ); } - packPaymasterData (paymaster: string, paymasterVerificationGasLimit: BigNumberish, postOpGasLimit: BigNumberish, paymasterData?: BytesLike): BytesLike { + packPaymasterData( + paymaster: string, + paymasterVerificationGasLimit: BigNumberish, + postOpGasLimit: BigNumberish, + paymasterData?: BytesLike + ): BytesLike { return ethers.utils.hexConcat([ paymaster, this.packUint(paymasterVerificationGasLimit, postOpGasLimit), - paymasterData ?? '0x' - ]) + paymasterData ?? "0x", + ]); } - async getPaymasterData(userOp: any, validUntil: string, validAfter: string, paymasterContract: Contract, signer: Wallet) { + async getPaymasterData( + userOp: any, + validUntil: string, + validAfter: string, + paymasterContract: Contract, + signer: Wallet + ) { // actual signing... const hash = await paymasterContract.getHash( userOp, @@ -45,32 +74,52 @@ export class Paymaster { const sig = await signer.signMessage(arrayify(hash)); const paymasterData = hexConcat([ - defaultAbiCoder.encode( - ['uint48', 'uint48'], - [validUntil, validAfter] - ), + defaultAbiCoder.encode(["uint48", "uint48"], [validUntil, validAfter]), sig, ]); return paymasterData; } - async signV07(userOp: any, validUntil: string, validAfter: string, entryPoint: string, paymasterAddress: string, - bundlerRpc: string, signer: Wallet, estimate: boolean, log?: FastifyBaseLogger) { + async signV07( + userOp: any, + validUntil: string, + validAfter: string, + entryPoint: string, + paymasterAddress: string, + bundlerRpc: string, + signer: Wallet, + estimate: boolean, + log?: FastifyBaseLogger + ) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const paymasterContract = new ethers.Contract(paymasterAddress, EtherspotAbiV07, provider); - if (!userOp.signature) userOp.signature = '0x'; - if (userOp.factory && userOp.factoryData) userOp.initCode = hexConcat([userOp.factory, userOp.factoryData ?? '']) + const paymasterContract = new ethers.Contract( + paymasterAddress, + EtherspotAbiV07, + provider + ); + if (!userOp.signature) userOp.signature = "0x"; + if (userOp.factory && userOp.factoryData) + userOp.initCode = hexConcat([userOp.factory, userOp.factoryData ?? ""]); if (!userOp.initCode) userOp.initCode = "0x"; if (estimate) { - const response = await provider.send('eth_estimateUserOperationGas', [userOp, entryPoint]); + const response = await provider.send("eth_estimateUserOperationGas", [ + userOp, + entryPoint, + ]); userOp.verificationGasLimit = response.verificationGasLimit; userOp.callGasLimit = response.callGasLimit; userOp.preVerificationGas = response.preVerificationGas; } - const accountGasLimits = this.packUint(userOp.verificationGasLimit, userOp.callGasLimit) - const gasFees = this.packUint(userOp.maxPriorityFeePerGas, userOp.maxFeePerGas); + const accountGasLimits = this.packUint( + userOp.verificationGasLimit, + userOp.callGasLimit + ); + const gasFees = this.packUint( + userOp.maxPriorityFeePerGas, + userOp.maxFeePerGas + ); let packedUserOp = { sender: userOp.sender, nonce: userOp.nonce, @@ -79,11 +128,21 @@ export class Paymaster { accountGasLimits: accountGasLimits, preVerificationGas: userOp.preVerificationGas, gasFees: gasFees, - paymasterAndData: this.packPaymasterData(paymasterAddress, BigNumber.from(30000), "0x1"), - signature: userOp.signature - } + paymasterAndData: this.packPaymasterData( + paymasterAddress, + BigNumber.from(30000), + "0x1" + ), + signature: userOp.signature, + }; - let paymasterData = await this.getPaymasterData(packedUserOp, validUntil, validAfter, paymasterContract, signer); + let paymasterData = await this.getPaymasterData( + packedUserOp, + validUntil, + validAfter, + paymasterContract, + signer + ); let returnValue; if (estimate) { returnValue = { @@ -93,23 +152,32 @@ export class Paymaster { verificationGasLimit: userOp.verificationGasLimit, callGasLimit: userOp.callGasLimit, paymasterVerificationGasLimit: BigNumber.from(30000).toString(), - paymasterPostOpGasLimit: "0x1" - } + paymasterPostOpGasLimit: "0x1", + }; } else { returnValue = { paymaster: paymasterAddress, paymasterData: paymasterData, - } + }; } return returnValue; } catch (err: any) { - if (log) log.error(err, 'signv07'); - throw new Error('Failed to process request to bundler. Please contact support team RawErrorMsg:' + err.message) + if (log) log.error(err, "signv07"); + throw new Error( + "Failed to process request to bundler. Please contact support team RawErrorMsg:" + + err.message + ); } } - async getPaymasterAndData(userOp: any, validUntil: string, validAfter: string, paymasterContract: Contract, signer: Wallet) { + async getPaymasterAndData( + userOp: any, + validUntil: string, + validAfter: string, + paymasterContract: Contract, + signer: Wallet + ) { // actual signing... const hash = await paymasterContract.getHash( userOp, @@ -121,30 +189,55 @@ export class Paymaster { const paymasterAndData = hexConcat([ paymasterContract.address, - defaultAbiCoder.encode( - ['uint48', 'uint48'], - [validUntil, validAfter] - ), + defaultAbiCoder.encode(["uint48", "uint48"], [validUntil, validAfter]), sig, ]); return paymasterAndData; } - async signV06(userOp: any, validUntil: string, validAfter: string, entryPoint: string, paymasterAddress: string, - bundlerRpc: string, signer: Wallet, estimate: boolean, log?: FastifyBaseLogger) { + async signV06( + userOp: any, + validUntil: string, + validAfter: string, + entryPoint: string, + paymasterAddress: string, + bundlerRpc: string, + signer: Wallet, + estimate: boolean, + log?: FastifyBaseLogger + ) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const paymasterContract = new ethers.Contract(paymasterAddress, EtherspotAbiV06, provider); - userOp.paymasterAndData = await this.getPaymasterAndData(userOp, validUntil, validAfter, paymasterContract, signer); - if (!userOp.signature) userOp.signature = '0x'; + const paymasterContract = new ethers.Contract( + paymasterAddress, + EtherspotAbiV06, + provider + ); + userOp.paymasterAndData = await this.getPaymasterAndData( + userOp, + validUntil, + validAfter, + paymasterContract, + signer + ); + if (!userOp.signature) userOp.signature = "0x"; if (estimate) { - const response = await provider.send('eth_estimateUserOperationGas', [userOp, entryPoint]); + const response = await provider.send("eth_estimateUserOperationGas", [ + userOp, + entryPoint, + ]); userOp.verificationGasLimit = response.verificationGasLimit; userOp.preVerificationGas = response.preVerificationGas; userOp.callGasLimit = response.callGasLimit; } - const paymasterAndData = await this.getPaymasterAndData(userOp, validUntil, validAfter, paymasterContract, signer); + const paymasterAndData = await this.getPaymasterAndData( + userOp, + validUntil, + validAfter, + paymasterContract, + signer + ); let returnValue; if (estimate) { returnValue = { @@ -152,22 +245,32 @@ export class Paymaster { verificationGasLimit: userOp.verificationGasLimit, preVerificationGas: userOp.preVerificationGas, callGasLimit: userOp.callGasLimit, - } + }; } else { returnValue = { - paymasterAndData - } + paymasterAndData, + }; } return returnValue; } catch (err: any) { - if (log) log.error(err, 'signV06'); - throw new Error('Failed to process request to bundler. Please contact support team RawErrorMsg:' + err.message) + if (log) log.error(err, "signV06"); + throw new Error( + "Failed to process request to bundler. Please contact support team RawErrorMsg:" + + err.message + ); } - } + } - async getPaymasterAndDataForMultiTokenPaymaster(userOp: any, validUntil: string, validAfter: string, feeToken: string, - ethPrice: string, paymasterContract: Contract, signer: Wallet) { + async getPaymasterAndDataForMultiTokenPaymaster( + userOp: any, + validUntil: string, + validAfter: string, + feeToken: string, + ethPrice: string, + paymasterContract: Contract, + signer: Wallet + ) { const exchangeRate = 1000000; // This is for setting min tokens required for the txn that gets validated on estimate const rate = ethers.BigNumber.from(exchangeRate).mul(ethPrice); const priceMarkup = this.multiTokenMarkUp; @@ -181,17 +284,24 @@ export class Paymaster { feeToken, ethers.constants.AddressZero, rate.toNumber().toFixed(0), - priceMarkup, + priceMarkup ); const sig = await signer.signMessage(arrayify(hash)); const paymasterAndData = hexConcat([ paymasterContract.address, - '0x00', + "0x00", defaultAbiCoder.encode( - ['uint48', 'uint48', 'address', 'address', 'uint256', 'uint32'], - [validUntil, validAfter, feeToken, ethers.constants.AddressZero, rate.toNumber().toFixed(0), priceMarkup] + ["uint48", "uint48", "address", "address", "uint256", "uint32"], + [ + validUntil, + validAfter, + feeToken, + ethers.constants.AddressZero, + rate.toNumber().toFixed(0), + priceMarkup, + ] ), sig, ]); @@ -199,50 +309,108 @@ export class Paymaster { return paymasterAndData; } - async signMultiTokenPaymaster(userOp: any, validUntil: string, validAfter: string, entryPoint: string, paymasterAddress: string, - feeToken: string, oracleAggregator: string, bundlerRpc: string, signer: Wallet, oracleName: string, log?: FastifyBaseLogger) { + async signMultiTokenPaymaster( + userOp: any, + validUntil: string, + validAfter: string, + entryPoint: string, + paymasterAddress: string, + feeToken: string, + oracleAggregator: string, + bundlerRpc: string, + signer: Wallet, + oracleName: string, + log?: FastifyBaseLogger + ) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const paymasterContract = new ethers.Contract(paymasterAddress, MultiTokenPaymasterAbi, provider); + const paymasterContract = new ethers.Contract( + paymasterAddress, + MultiTokenPaymasterAbi, + provider + ); let ethPrice = ""; if (oracleName === "orochi") { - const oracleContract = new ethers.Contract(oracleAggregator, OrochiOracleAbi, provider); - const result = await oracleContract.getLatestData(1, ethers.utils.hexlify(ethers.utils.toUtf8Bytes('ETH')).padEnd(42, '0')) + const oracleContract = new ethers.Contract( + oracleAggregator, + OrochiOracleAbi, + provider + ); + const result = await oracleContract.getLatestData( + 1, + ethers.utils.hexlify(ethers.utils.toUtf8Bytes("ETH")).padEnd(42, "0") + ); ethPrice = Number(ethers.utils.formatEther(result)).toFixed(0); } else { - const chainlinkContract = new ethers.Contract(oracleAggregator, ChainlinkOracleAbi, provider); + const chainlinkContract = new ethers.Contract( + oracleAggregator, + ChainlinkOracleAbi, + provider + ); const decimals = await chainlinkContract.decimals(); const result = await chainlinkContract.latestAnswer(); - ethPrice = Number(ethers.utils.formatUnits(result, decimals)).toFixed(0); + ethPrice = Number(ethers.utils.formatUnits(result, decimals)).toFixed( + 0 + ); } - userOp.paymasterAndData = await this.getPaymasterAndDataForMultiTokenPaymaster(userOp, validUntil, validAfter, feeToken, ethPrice, paymasterContract, signer); - - if (!userOp.signature) userOp.signature = '0x'; - const response = await provider.send('eth_estimateUserOperationGas', [userOp, entryPoint]); + userOp.paymasterAndData = + await this.getPaymasterAndDataForMultiTokenPaymaster( + userOp, + validUntil, + validAfter, + feeToken, + ethPrice, + paymasterContract, + signer + ); + + if (!userOp.signature) userOp.signature = "0x"; + const response = await provider.send("eth_estimateUserOperationGas", [ + userOp, + entryPoint, + ]); userOp.verificationGasLimit = response.verificationGasLimit; userOp.preVerificationGas = response.preVerificationGas; userOp.callGasLimit = response.callGasLimit; - const paymasterAndData = await this.getPaymasterAndDataForMultiTokenPaymaster(userOp, validUntil, validAfter, feeToken, ethPrice, paymasterContract, signer); + const paymasterAndData = + await this.getPaymasterAndDataForMultiTokenPaymaster( + userOp, + validUntil, + validAfter, + feeToken, + ethPrice, + paymasterContract, + signer + ); const returnValue = { paymasterAndData, verificationGasLimit: response.verificationGasLimit, preVerificationGas: response.preVerificationGas, callGasLimit: response.callGasLimit, - } + }; return returnValue; } catch (err: any) { - if (log) log.error(err, 'signCombinedPaymaster'); - throw new Error('Failed to process request to bundler. Please contact support team RawErrorMsg:' + err.message) + if (log) log.error(err, "signCombinedPaymaster"); + throw new Error( + "Failed to process request to bundler. Please contact support team RawErrorMsg:" + + err.message + ); } } - async pimlico(userOp: any, bundlerRpc: string, entryPoint: string, PaymasterAddress: string, log?: FastifyBaseLogger) { + async pimlico( + userOp: any, + bundlerRpc: string, + entryPoint: string, + PaymasterAddress: string, + log?: FastifyBaseLogger + ) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const erc20Paymaster = new PimlicoPaymaster(PaymasterAddress, provider) - if (!userOp.signature) userOp.signature = '0x'; + const erc20Paymaster = new PimlicoPaymaster(PaymasterAddress, provider); + if (!userOp.signature) userOp.signature = "0x"; // The minimum ABI to get the ERC20 Token balance const minABI = [ @@ -250,27 +418,46 @@ export class Paymaster { { constant: true, - inputs: [{ name: '_owner', type: 'address' }], + inputs: [{ name: "_owner", type: "address" }], - name: 'balanceOf', + name: "balanceOf", - outputs: [{ name: 'balance', type: 'uint256' }], + outputs: [{ name: "balance", type: "uint256" }], - type: 'function', + type: "function", }, - ] - const tokenAmountRequired = await erc20Paymaster.calculateTokenAmount(userOp); - const tokenContract = new Contract(await erc20Paymaster.tokenAddress, minABI, provider) + ]; + 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}`) + 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) + 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(); + const response = await provider.send("eth_estimateUserOperationGas", [ + userOp, + entryPoint, + ]); + userOp.verificationGasLimit = ethers.BigNumber.from( + response.verificationGasLimit + ) + .add(100000) + .toString(); userOp.preVerificationGas = response.preVerificationGas; userOp.callGasLimit = response.callGasLimit; paymasterAndData = await erc20Paymaster.generatePaymasterAndData(userOp); @@ -282,35 +469,62 @@ export class Paymaster { callGasLimit: response.callGasLimit, }; } catch (err: any) { - if (err.message.includes('The required token amount')) throw new Error(err.message); - if (log) log.error(err, 'pimlico'); - throw new Error('Failed to process request to bundler. Please contact support team RawErrorMsg: ' + err.message) + if (err.message.includes("The required token amount")) + throw new Error(err.message); + if (log) log.error(err, "pimlico"); + throw new Error( + "Failed to process request to bundler. Please contact support team RawErrorMsg: " + + err.message + ); } } - async pimlicoAddress(gasToken: string, chainId: number, log?: FastifyBaseLogger) { + async pimlicoAddress( + gasToken: string, + chainId: number, + log?: FastifyBaseLogger + ) { try { return { - message: PAYMASTER_ADDRESS[chainId][gasToken] ?? 'Requested Token Paymaster is not available/deployed', - } + message: + PAYMASTER_ADDRESS[chainId][gasToken] ?? + "Requested Token Paymaster is not available/deployed", + }; } catch (err: any) { - if (log) log.error(err, 'pimlicoAddress'); - throw new Error(err.message) + if (log) log.error(err, "pimlicoAddress"); + throw new Error(err.message); } } - async whitelistAddresses(address: string[], paymasterAddress: string, bundlerRpc: string, relayerKey: string, chainId: number, log?: FastifyBaseLogger) { + async whitelistAddresses( + address: string[], + paymasterAddress: string, + bundlerRpc: string, + relayerKey: string, + chainId: number, + log?: FastifyBaseLogger + ) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const paymasterContract = new ethers.Contract(paymasterAddress, EtherspotAbiV06, provider); - const signer = new Wallet(relayerKey, provider) + const paymasterContract = new ethers.Contract( + paymasterAddress, + EtherspotAbiV06, + provider + ); + const signer = new Wallet(relayerKey, provider); for (let i = 0; i < address.length; i++) { - const isAdded = await paymasterContract.check(signer.address, address[i]); + const isAdded = await paymasterContract.check( + signer.address, + address[i] + ); if (isAdded) { - throw new Error(`${address[i]} already whitelisted`) + throw new Error(`${address[i]} already whitelisted`); } } - const encodedData = paymasterContract.interface.encodeFunctionData('addBatchToWhitelist', [address]); + const encodedData = paymasterContract.interface.encodeFunctionData( + "addBatchToWhitelist", + [address] + ); const etherscanFeeData = await getEtherscanFee(chainId); let feeData; @@ -318,9 +532,15 @@ export class Paymaster { feeData = etherscanFeeData; } else { feeData = await provider.getFeeData(); - feeData.gasPrice = feeData.gasPrice ? feeData.gasPrice.add(this.feeMarkUp) : null; - feeData.maxFeePerGas = feeData.maxFeePerGas ? feeData.maxFeePerGas.add(this.feeMarkUp) : null; - feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) : null; + feeData.gasPrice = feeData.gasPrice + ? feeData.gasPrice.add(this.feeMarkUp) + : null; + feeData.maxFeePerGas = feeData.maxFeePerGas + ? feeData.maxFeePerGas.add(this.feeMarkUp) + : null; + feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas + ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) + : null; } let tx: providers.TransactionResponse; @@ -329,7 +549,7 @@ export class Paymaster { to: paymasterAddress, data: encodedData, gasPrice: feeData.gasPrice ?? undefined, - }) + }); } else { tx = await signer.sendTransaction({ to: paymasterAddress, @@ -343,37 +563,63 @@ export class Paymaster { // await tx.wait(); return { - message: `Successfully whitelisted with transaction Hash ${tx.hash}` + message: `Successfully whitelisted with transaction Hash ${tx.hash}`, }; } catch (err: any) { - if (err.message.includes('already whitelisted')) throw new Error(err.message); - if (log) log.error(err, 'whitelistAddresses') - throw new Error(ErrorMessage.ERROR_ON_SUBMITTING_TXN + ` RawErrorMsg: ${err.message}`); + if (err.message.includes("already whitelisted")) + throw new Error(err.message); + if (log) log.error(err, "whitelistAddresses"); + throw new Error( + ErrorMessage.ERROR_ON_SUBMITTING_TXN + ` RawErrorMsg: ${err.message}` + ); } } - async removeWhitelistAddress(address: string[], paymasterAddress: string, bundlerRpc: string, relayerKey: string, chainId: number, log?: FastifyBaseLogger) { + async removeWhitelistAddress( + address: string[], + paymasterAddress: string, + bundlerRpc: string, + relayerKey: string, + chainId: number, + log?: FastifyBaseLogger + ) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const paymasterContract = new ethers.Contract(paymasterAddress, EtherspotAbiV06, provider); - const signer = new Wallet(relayerKey, provider) + const paymasterContract = new ethers.Contract( + paymasterAddress, + EtherspotAbiV06, + provider + ); + const signer = new Wallet(relayerKey, provider); for (let i = 0; i < address.length; i++) { - const isAdded = await paymasterContract.check(signer.address, address[i]); + const isAdded = await paymasterContract.check( + signer.address, + address[i] + ); if (!isAdded) { - throw new Error(`${address[i]} is not whitelisted`) + throw new Error(`${address[i]} is not whitelisted`); } } - const encodedData = paymasterContract.interface.encodeFunctionData('removeBatchFromWhitelist', [address]); + const encodedData = paymasterContract.interface.encodeFunctionData( + "removeBatchFromWhitelist", + [address] + ); const etherscanFeeData = await getEtherscanFee(chainId); let feeData; if (etherscanFeeData) { feeData = etherscanFeeData; } else { feeData = await provider.getFeeData(); - feeData.gasPrice = feeData.gasPrice ? feeData.gasPrice.add(this.feeMarkUp) : null; - feeData.maxFeePerGas = feeData.maxFeePerGas ? feeData.maxFeePerGas.add(this.feeMarkUp) : null; - feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) : null; + feeData.gasPrice = feeData.gasPrice + ? feeData.gasPrice.add(this.feeMarkUp) + : null; + feeData.maxFeePerGas = feeData.maxFeePerGas + ? feeData.maxFeePerGas.add(this.feeMarkUp) + : null; + feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas + ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) + : null; } let tx: providers.TransactionResponse; @@ -382,7 +628,7 @@ export class Paymaster { to: paymasterAddress, data: encodedData, gasPrice: feeData.gasPrice ?? undefined, - }) + }); } else { tx = await signer.sendTransaction({ to: paymasterAddress, @@ -396,49 +642,82 @@ export class Paymaster { // await tx.wait(); return { - message: `Successfully removed whitelisted addresses with transaction Hash ${tx.hash}` + message: `Successfully removed whitelisted addresses with transaction Hash ${tx.hash}`, }; } catch (err: any) { - if (err.message.includes('is not whitelisted')) throw new Error(err.message); - if (log) log.error(err, 'removeWhitelistAddress'); + if (err.message.includes("is not whitelisted")) + throw new Error(err.message); + if (log) log.error(err, "removeWhitelistAddress"); throw new Error(ErrorMessage.ERROR_ON_SUBMITTING_TXN); } } - async checkWhitelistAddress(accountAddress: string, paymasterAddress: string, bundlerRpc: string, relayerKey: string, log?: FastifyBaseLogger) { + async checkWhitelistAddress( + accountAddress: string, + paymasterAddress: string, + bundlerRpc: string, + relayerKey: string, + log?: FastifyBaseLogger + ) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const signer = new Wallet(relayerKey, provider) - const paymasterContract = new ethers.Contract(paymasterAddress, EtherspotAbiV06, provider); + const signer = new Wallet(relayerKey, provider); + const paymasterContract = new ethers.Contract( + paymasterAddress, + EtherspotAbiV06, + provider + ); return paymasterContract.check(signer.address, accountAddress); } catch (err) { - if (log) log.error(err, 'checkWhitelistAddress'); + if (log) log.error(err, "checkWhitelistAddress"); throw new Error(ErrorMessage.RPC_ERROR); } } - async deposit(amount: string, paymasterAddress: string, bundlerRpc: string, relayerKey: string, chainId: number, log?: FastifyBaseLogger) { + async deposit( + amount: string, + paymasterAddress: string, + bundlerRpc: string, + relayerKey: string, + chainId: number, + log?: FastifyBaseLogger + ) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const paymasterContract = new ethers.Contract(paymasterAddress, EtherspotAbiV06, provider); - const signer = new Wallet(relayerKey, provider) + const paymasterContract = new ethers.Contract( + paymasterAddress, + EtherspotAbiV06, + provider + ); + const signer = new Wallet(relayerKey, provider); const balance = await signer.getBalance(); const amountInWei = ethers.utils.parseEther(amount.toString()); if (amountInWei.gte(balance)) - throw new Error(`${signer.address} Balance is less than the amount to be deposited`) + throw new Error( + `${signer.address} Balance is less than the amount to be deposited` + ); - const encodedData = paymasterContract.interface.encodeFunctionData('depositFunds', []); + const encodedData = paymasterContract.interface.encodeFunctionData( + "depositFunds", + [] + ); const etherscanFeeData = await getEtherscanFee(chainId); - console.log('etherscanFeeData: ', etherscanFeeData); + console.log("etherscanFeeData: ", etherscanFeeData); let feeData; if (etherscanFeeData) { feeData = etherscanFeeData; } else { feeData = await provider.getFeeData(); - feeData.gasPrice = feeData.gasPrice ? feeData.gasPrice.add(this.feeMarkUp) : null; - feeData.maxFeePerGas = feeData.maxFeePerGas ? feeData.maxFeePerGas.add(this.feeMarkUp) : null; - feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) : null; + feeData.gasPrice = feeData.gasPrice + ? feeData.gasPrice.add(this.feeMarkUp) + : null; + feeData.maxFeePerGas = feeData.maxFeePerGas + ? feeData.maxFeePerGas.add(this.feeMarkUp) + : null; + feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas + ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) + : null; } let tx: providers.TransactionResponse; @@ -448,7 +727,7 @@ export class Paymaster { data: encodedData, value: amountInWei, gasPrice: feeData.gasPrice ?? undefined, - }) + }); } else { tx = await signer.sendTransaction({ to: paymasterAddress, @@ -460,14 +739,17 @@ export class Paymaster { }); } // commented the below line to avoid timeouts for long delays in transaction confirmation. - // await tx.wait(); + // await tx.wait(); return { - message: `Successfully deposited with transaction Hash ${tx.hash}` + message: `Successfully deposited with transaction Hash ${tx.hash}`, }; } catch (err: any) { - if (log) log.error(err, 'deposit'); - if (err.message.includes('Balance is less than the amount to be deposited')) throw new Error(err.message); + if (log) log.error(err, "deposit"); + 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.test.ts b/backend/src/paymaster/pimlico.test.ts index d83e0a4..0e372ea 100644 --- a/backend/src/paymaster/pimlico.test.ts +++ b/backend/src/paymaster/pimlico.test.ts @@ -1,24 +1,31 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { providers, ethers } from "ethers"; import { PimlicoPaymaster, getERC20Paymaster } from "./pimlico.js"; -import { NATIVE_ASSET, ORACLE_ADDRESS, TOKEN_ADDRESS } from "../../src/constants/Pimlico.js"; +import { + NATIVE_ASSET, + ORACLE_ADDRESS, + TOKEN_ADDRESS, +} from "../../src/constants/Pimlico.js"; -describe('PimlicoPaymaster on Mumbai', () => { - const paymasterAddress = '0x32aCDFeA07a614E52403d2c1feB747aa8079A353'; // Mumbai Etherspot Paymaster Address +describe("PimlicoPaymaster on Mumbai", () => { + const paymasterAddress = "0x32aCDFeA07a614E52403d2c1feB747aa8079A353"; // Mumbai Etherspot Paymaster Address const entryPointAddress = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // EntryPoint v0.6 as default - const bundlerUrl = 'https://mumbai-bundler.etherspot.io'; + const bundlerUrl = "https://mumbai-bundler.etherspot.io"; const userOp = { - sender: '0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321', - nonce: '0x1', - initCode: '0x', - callData: '0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000', - callGasLimit: '0x88b8', - verificationGasLimit: '0x186a0', - maxFeePerGas: '0x6fc23ac10', - maxPriorityFeePerGas: '0x6fc23ac00', - paymasterAndData: '0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', - signature: '0x0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', - preVerificationGas: '0xc6c4' + sender: "0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321", + nonce: "0x1", + initCode: "0x", + callData: + "0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", + callGasLimit: "0x88b8", + verificationGasLimit: "0x186a0", + maxFeePerGas: "0x6fc23ac10", + maxPriorityFeePerGas: "0x6fc23ac00", + paymasterAndData: + "0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101", + signature: + "0x0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101", + preVerificationGas: "0xc6c4", }; const ERC20PaymasterBuildOptions = { @@ -28,98 +35,131 @@ describe('PimlicoPaymaster on Mumbai', () => { tokenAddress: TOKEN_ADDRESS[80001].USDC, tokenOracle: ORACLE_ADDRESS[80001].USDC, owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", - deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680" - } + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680", + }; const provider = new providers.JsonRpcProvider(bundlerUrl); const pimlicoPaymaster = new PimlicoPaymaster(paymasterAddress, provider); - test('SMOKE: validate the calculateTokenAmount function with valid details', async () => { + test.skip("SMOKE: validate the calculateTokenAmount function with valid details", async () => { try { - const calculateTokenAmountResponse = await pimlicoPaymaster.calculateTokenAmount(userOp); + const calculateTokenAmountResponse = + await pimlicoPaymaster.calculateTokenAmount(userOp); try { - expect(calculateTokenAmountResponse).toHaveProperty('_hex'); + expect(calculateTokenAmountResponse).toHaveProperty("_hex"); } catch (e) { - fail("The _hex details is not displayed in the calculate token amount response") + fail( + "The _hex details is not displayed in the calculate token amount response" + ); } - } catch (e) { - fail('An error is displayed while performing calculateTokenAmount action.') + fail( + "An error is displayed while performing calculateTokenAmount action." + ); } }); - test('SMOKE: validate the generatePaymasterAndData function with valid details', async () => { + test.skip("SMOKE: validate the generatePaymasterAndData function with valid details", async () => { try { - const generatePaymasterAndDataResponse = await pimlicoPaymaster.generatePaymasterAndData(userOp); + const generatePaymasterAndDataResponse = + await pimlicoPaymaster.generatePaymasterAndData(userOp); try { - expect(generatePaymasterAndDataResponse.length.toString()).toMatch('106'); + expect(generatePaymasterAndDataResponse.length.toString()).toMatch( + "106" + ); } catch (e) { - fail("The paymaster and data details is not displayed in the generatePaymasterAndData response") + fail( + "The paymaster and data details is not displayed in the generatePaymasterAndData response" + ); } } catch (e) { - fail('An error is displayed while performing generatePaymasterAndData action.') + fail( + "An error is displayed while performing generatePaymasterAndData action." + ); } }); - test('SMOKE: validate the getERC20Paymaster function with valid details', async () => { - const erc20 = 'USDC'; + test.skip("SMOKE: validate the getERC20Paymaster function with valid details", async () => { + const erc20 = "USDC"; try { - const getERC20PaymasterResponse = await getERC20Paymaster(provider, erc20, entryPointAddress); - + const getERC20PaymasterResponse = await getERC20Paymaster( + provider, + erc20, + entryPointAddress + ); + try { - expect(getERC20PaymasterResponse).toHaveProperty('paymasterAddress'); + expect(getERC20PaymasterResponse).toHaveProperty("paymasterAddress"); } catch (e) { - fail("The paymasterAddress details is not displayed in the getERC20Paymaster response") + fail( + "The paymasterAddress details is not displayed in the getERC20Paymaster response" + ); } } catch (e) { - fail('An error is displayed while performing getERC20Paymaster action.') + fail("An error is displayed while performing getERC20Paymaster action."); } }); - test('SMOKE: validate the getERC20Paymaster function with valid details and ERC20 paymaster build options', async () => { - const erc20 = 'USDC'; + test.skip("SMOKE: validate the getERC20Paymaster function with valid details and ERC20 paymaster build options", async () => { + const erc20 = "USDC"; try { - const getERC20PaymasterResponse = await getERC20Paymaster(provider, erc20, entryPointAddress, ERC20PaymasterBuildOptions); - + const getERC20PaymasterResponse = await getERC20Paymaster( + provider, + erc20, + entryPointAddress, + ERC20PaymasterBuildOptions + ); + try { - expect(getERC20PaymasterResponse).toHaveProperty('paymasterAddress'); + expect(getERC20PaymasterResponse).toHaveProperty("paymasterAddress"); } catch (e) { - fail("The paymasterAddress details is not displayed in the getERC20Paymaster response") + fail( + "The paymasterAddress details is not displayed in the getERC20Paymaster response" + ); } - } catch (e) { - fail('An error is displayed while performing getERC20Paymaster action.') + fail("An error is displayed while performing getERC20Paymaster action."); } }); - test('REGRESSION: validate the getERC20Paymaster function with without owner', async () => { - const erc20 = 'USDC'; + test.skip("REGRESSION: validate the getERC20Paymaster function with without owner", async () => { + const erc20 = "USDC"; const ERC20PaymasterBuildOptions = { entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", nativeAsset: NATIVE_ASSET[80001], nativeAssetOracle: ORACLE_ADDRESS[80001].MATIC, tokenAddress: TOKEN_ADDRESS[80001].USDC, tokenOracle: ORACLE_ADDRESS[80001].USDC, - deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680" - } + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680", + }; try { - await getERC20Paymaster(provider, erc20, entryPointAddress, ERC20PaymasterBuildOptions); - fail('The getERC20Paymaster function is worked, however the onwer is not available.') - + await getERC20Paymaster( + provider, + erc20, + entryPointAddress, + ERC20PaymasterBuildOptions + ); + fail( + "The getERC20Paymaster function is worked, however the onwer is not available." + ); } catch (e: any) { - const actualMessage = 'Owner must be provided'; + const actualMessage = "Owner must be provided"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The owner is not available while using the getERC20Paymaster function.') + console.log( + "The owner is not available while using the getERC20Paymaster function." + ); } else { - fail('The respective validation is not displayed when owner not added while using the getERC20Paymaster function.') + fail( + "The respective validation is not displayed when owner not added while using the getERC20Paymaster function." + ); } } }); - test('REGRESSION: validate the getERC20Paymaster function with without deployer', async () => { - const erc20 = 'USDC'; + test.skip("REGRESSION: validate the getERC20Paymaster function with without deployer", async () => { + const erc20 = "USDC"; const ERC20PaymasterBuildOptions = { entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", nativeAsset: NATIVE_ASSET[80001], @@ -127,24 +167,34 @@ describe('PimlicoPaymaster on Mumbai', () => { tokenAddress: TOKEN_ADDRESS[80001].USDC, tokenOracle: ORACLE_ADDRESS[80001].USDC, owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", - } + }; try { - await getERC20Paymaster(provider, erc20, entryPointAddress, ERC20PaymasterBuildOptions); - fail('The getERC20Paymaster function is worked, however the deployer is not available.') - + await getERC20Paymaster( + provider, + erc20, + entryPointAddress, + ERC20PaymasterBuildOptions + ); + fail( + "The getERC20Paymaster function is worked, however the deployer is not available." + ); } catch (e: any) { - const actualMessage = 'Deployer must be provided'; + const actualMessage = "Deployer must be provided"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The deployer is not available while using the getERC20Paymaster function.') + console.log( + "The deployer is not available while using the getERC20Paymaster function." + ); } else { - fail('The respective validation is not displayed when deployer not added while using the getERC20Paymaster function.') + fail( + "The respective validation is not displayed when deployer not added while using the getERC20Paymaster function." + ); } } }); - test('REGRESSION: validate the getERC20Paymaster function with invalid native asset', async () => { - const erc20 = 'USDC'; + test.skip("REGRESSION: validate the getERC20Paymaster function with invalid native asset", async () => { + const erc20 = "USDC"; const ERC20PaymasterBuildOptions = { entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", nativeAsset: "", @@ -152,24 +202,35 @@ describe('PimlicoPaymaster on Mumbai', () => { tokenAddress: TOKEN_ADDRESS[80001].USDC, tokenOracle: ORACLE_ADDRESS[80001].USDC, owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", - deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680" - } + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680", + }; try { - await getERC20Paymaster(provider, erc20, entryPointAddress, ERC20PaymasterBuildOptions); - fail('The getERC20Paymaster function is worked, however the Native asset is invalid.') + await getERC20Paymaster( + provider, + erc20, + entryPointAddress, + ERC20PaymasterBuildOptions + ); + fail( + "The getERC20Paymaster function is worked, however the Native asset is invalid." + ); } catch (e: any) { - const actualMessage = 'Native asset not found - chainId'; + const actualMessage = "Native asset not found - chainId"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The Native asset is invalid while using the getERC20Paymaster function.') + console.log( + "The Native asset is invalid while using the getERC20Paymaster function." + ); } else { - fail('The respective validation is not displayed when invalid Native asset added while using the getERC20Paymaster function.') + fail( + "The respective validation is not displayed when invalid Native asset added while using the getERC20Paymaster function." + ); } } }); - test('REGRESSION: validate the getERC20Paymaster function with invalid native asset oracle', async () => { - const erc20 = 'USDC'; + test.skip("REGRESSION: validate the getERC20Paymaster function with invalid native asset oracle", async () => { + const erc20 = "USDC"; const ERC20PaymasterBuildOptions = { entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", nativeAsset: "80002", @@ -177,25 +238,36 @@ describe('PimlicoPaymaster on Mumbai', () => { tokenAddress: TOKEN_ADDRESS[80001].USDC, tokenOracle: ORACLE_ADDRESS[80001].USDC, owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", - deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680" - } + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680", + }; try { - await getERC20Paymaster(provider, erc20, entryPointAddress, ERC20PaymasterBuildOptions); - fail('The getERC20Paymaster function is worked, however the Native asset oracle is invalid.') + await getERC20Paymaster( + provider, + erc20, + entryPointAddress, + ERC20PaymasterBuildOptions + ); + fail( + "The getERC20Paymaster function is worked, however the Native asset oracle is invalid." + ); } catch (e: any) { - const actualMessage = 'Native asset oracle not found - chainId'; + const actualMessage = "Native asset oracle not found - chainId"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The Native asset oracle is invalid while using the getERC20Paymaster function.') + console.log( + "The Native asset oracle is invalid while using the getERC20Paymaster function." + ); } else { - fail('The respective validation is not displayed when invalid Native asset oracle added while using the getERC20Paymaster function.') + fail( + "The respective validation is not displayed when invalid Native asset oracle added while using the getERC20Paymaster function." + ); } } }); - test('REGRESSION: validate the getERC20Paymaster function with native asset oracle not deployed', async () => { + test.skip("REGRESSION: validate the getERC20Paymaster function with native asset oracle not deployed", async () => { const randomAddress = ethers.Wallet.createRandom(); - const erc20 = 'USDC'; + const erc20 = "USDC"; const ERC20PaymasterBuildOptions = { entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", nativeAsset: NATIVE_ASSET[80001], @@ -203,24 +275,35 @@ describe('PimlicoPaymaster on Mumbai', () => { tokenAddress: TOKEN_ADDRESS[80001].USDC, tokenOracle: ORACLE_ADDRESS[80001].USDC, owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", - deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680" - } + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680", + }; try { - await getERC20Paymaster(provider, erc20, entryPointAddress, ERC20PaymasterBuildOptions); - fail('The getERC20Paymaster function is worked, however the Native asset oracle is not deployed.') + await getERC20Paymaster( + provider, + erc20, + entryPointAddress, + ERC20PaymasterBuildOptions + ); + fail( + "The getERC20Paymaster function is worked, however the Native asset oracle is not deployed." + ); } catch (e: any) { - const actualMessage = 'Oracle for MATIC on chainId 80001 is not deployed'; + const actualMessage = "Oracle for MATIC on chainId 80001 is not deployed"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The Native asset oracle is not deployed while using the getERC20Paymaster function.') + console.log( + "The Native asset oracle is not deployed while using the getERC20Paymaster function." + ); } else { - fail('The respective validation is not displayed when Native asset oracle not deployed while using the getERC20Paymaster function.') + fail( + "The respective validation is not displayed when Native asset oracle not deployed while using the getERC20Paymaster function." + ); } } }); - test('REGRESSION: validate the getERC20Paymaster function with invalid token address', async () => { - const erc20 = 'USDC'; + test.skip("REGRESSION: validate the getERC20Paymaster function with invalid token address", async () => { + const erc20 = "USDC"; const ERC20PaymasterBuildOptions = { entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", nativeAsset: NATIVE_ASSET[80001], @@ -228,25 +311,36 @@ describe('PimlicoPaymaster on Mumbai', () => { tokenAddress: "", tokenOracle: ORACLE_ADDRESS[80001].USDC, owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", - deployer: "0x4337000c2828f5260d8921fd25829f606b9e8685" - } + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8685", + }; try { - await getERC20Paymaster(provider, erc20, entryPointAddress, ERC20PaymasterBuildOptions); - fail('The getERC20Paymaster function is worked, however the token address is invalid.') + await getERC20Paymaster( + provider, + erc20, + entryPointAddress, + ERC20PaymasterBuildOptions + ); + fail( + "The getERC20Paymaster function is worked, however the token address is invalid." + ); } catch (e: any) { - const actualMessage = 'Token USDC not supported on chainId'; + const actualMessage = "Token USDC not supported on chainId"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The token address is invalid while using the getERC20Paymaster function.') + console.log( + "The token address is invalid while using the getERC20Paymaster function." + ); } else { - fail('The respective validation is not displayed when invalid token address added while using the getERC20Paymaster function.') + fail( + "The respective validation is not displayed when invalid token address added while using the getERC20Paymaster function." + ); } } }); - test('REGRESSION: validate the getERC20Paymaster function with token address not deployed', async () => { + test.skip("REGRESSION: validate the getERC20Paymaster function with token address not deployed", async () => { const randomAddress = ethers.Wallet.createRandom(); - const erc20 = 'USDC'; + const erc20 = "USDC"; const ERC20PaymasterBuildOptions = { entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", nativeAsset: NATIVE_ASSET[80001], @@ -254,24 +348,35 @@ describe('PimlicoPaymaster on Mumbai', () => { tokenAddress: randomAddress.address, tokenOracle: ORACLE_ADDRESS[80001].USDC, owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", - deployer: "0x4337000c2828f5260d8921fd25829f606b9e8685" - } + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8685", + }; try { - await getERC20Paymaster(provider, erc20, entryPointAddress, ERC20PaymasterBuildOptions); - fail('The getERC20Paymaster function is worked, however the token address is not deployed.') + await getERC20Paymaster( + provider, + erc20, + entryPointAddress, + ERC20PaymasterBuildOptions + ); + fail( + "The getERC20Paymaster function is worked, however the token address is not deployed." + ); } catch (e: any) { - const actualMessage = 'Token USDC on 80001 is not deployed'; + const actualMessage = "Token USDC on 80001 is not deployed"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The token address is not deployed while using the getERC20Paymaster function.') + console.log( + "The token address is not deployed while using the getERC20Paymaster function." + ); } else { - fail('The respective validation is not displayed when token address not deployed while using the getERC20Paymaster function.') + fail( + "The respective validation is not displayed when token address not deployed while using the getERC20Paymaster function." + ); } } }); - test('REGRESSION: validate the getERC20Paymaster function with invalid token oracle', async () => { - const erc20 = 'USDC'; + test.skip("REGRESSION: validate the getERC20Paymaster function with invalid token oracle", async () => { + const erc20 = "USDC"; const ERC20PaymasterBuildOptions = { entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", nativeAsset: NATIVE_ASSET[80001], @@ -279,25 +384,37 @@ describe('PimlicoPaymaster on Mumbai', () => { tokenAddress: ORACLE_ADDRESS[80001].USDC, tokenOracle: "", owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", - deployer: "0x4337000c2828f5260d8921fd25829f606b9e8685" - } + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8685", + }; try { - await getERC20Paymaster(provider, erc20, entryPointAddress, ERC20PaymasterBuildOptions); - fail('The getERC20Paymaster function is worked, however the token oracle is invalid.') + await getERC20Paymaster( + provider, + erc20, + entryPointAddress, + ERC20PaymasterBuildOptions + ); + fail( + "The getERC20Paymaster function is worked, however the token oracle is invalid." + ); } catch (e: any) { - const actualMessage = 'Oracle for USDC not found, not supported on chainId'; + const actualMessage = + "Oracle for USDC not found, not supported on chainId"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The token oracle is invalid while using the getERC20Paymaster function.') + console.log( + "The token oracle is invalid while using the getERC20Paymaster function." + ); } else { - fail('The respective validation is not displayed when invalid token oracle added while using the getERC20Paymaster function.') + fail( + "The respective validation is not displayed when invalid token oracle added while using the getERC20Paymaster function." + ); } } }); - test('REGRESSION: validate the getERC20Paymaster function with token oracle not deployed', async () => { + test.skip("REGRESSION: validate the getERC20Paymaster function with token oracle not deployed", async () => { const randomAddress = ethers.Wallet.createRandom(); - const erc20 = 'USDC'; + const erc20 = "USDC"; const ERC20PaymasterBuildOptions = { entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", nativeAsset: NATIVE_ASSET[80001], @@ -305,25 +422,36 @@ describe('PimlicoPaymaster on Mumbai', () => { tokenAddress: ORACLE_ADDRESS[80001].USDC, tokenOracle: randomAddress.address, owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", - deployer: "0x4337000c2828f5260d8921fd25829f606b9e8685" - } + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8685", + }; try { - await getERC20Paymaster(provider, erc20, entryPointAddress, ERC20PaymasterBuildOptions); - fail('The getERC20Paymaster function is worked, however the token oracle is not deployed.') + await getERC20Paymaster( + provider, + erc20, + entryPointAddress, + ERC20PaymasterBuildOptions + ); + fail( + "The getERC20Paymaster function is worked, however the token oracle is not deployed." + ); } catch (e: any) { - const actualMessage = 'Oracle for USDC on 80001 is not deployed'; + const actualMessage = "Oracle for USDC on 80001 is not deployed"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The token oracle is not deployed while using the getERC20Paymaster function.') + console.log( + "The token oracle is not deployed while using the getERC20Paymaster function." + ); } else { - fail('The respective validation is not displayed when token oracle not deployed while using the getERC20Paymaster function.') + fail( + "The respective validation is not displayed when token oracle not deployed while using the getERC20Paymaster function." + ); } } }); - test('REGRESSION: validate the getERC20Paymaster function with ERC20Paymaster not deployed', async () => { + test.skip("REGRESSION: validate the getERC20Paymaster function with ERC20Paymaster not deployed", async () => { const randomAddress = ethers.Wallet.createRandom(); - const erc20 = 'USDC'; + const erc20 = "USDC"; const ERC20PaymasterBuildOptions = { entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", nativeAsset: NATIVE_ASSET[80001], @@ -331,19 +459,30 @@ describe('PimlicoPaymaster on Mumbai', () => { tokenAddress: ORACLE_ADDRESS[80001].USDC, tokenOracle: ORACLE_ADDRESS[80001].USDC, owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", - deployer: randomAddress - } + deployer: randomAddress, + }; try { - await getERC20Paymaster(provider, erc20, entryPointAddress, ERC20PaymasterBuildOptions); - fail('The getERC20Paymaster function is worked, however the ERC20Paymaster not deployed.') + await getERC20Paymaster( + provider, + erc20, + entryPointAddress, + ERC20PaymasterBuildOptions + ); + fail( + "The getERC20Paymaster function is worked, however the ERC20Paymaster not deployed." + ); } catch (e: any) { - const actualMessage = 'ERC20Paymaster not deployed at'; + const actualMessage = "ERC20Paymaster not deployed at"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The ERC20Paymaster not deployed while using the getERC20Paymaster function.') + console.log( + "The ERC20Paymaster not deployed while using the getERC20Paymaster function." + ); } else { - fail('The respective validation is not displayed when ERC20Paymaster not deployed while using the getERC20Paymaster function.') + fail( + "The respective validation is not displayed when ERC20Paymaster not deployed while using the getERC20Paymaster function." + ); } } }); -}); \ No newline at end of file +}); diff --git a/backend/src/utils/common.ts b/backend/src/utils/common.ts index bfc2624..89dd146 100644 --- a/backend/src/utils/common.ts +++ b/backend/src/utils/common.ts @@ -1,32 +1,52 @@ import { FastifyBaseLogger, FastifyRequest } from "fastify"; import { BigNumber, ethers } from "ethers"; import { Database } from "sqlite3"; -import SupportedNetworks from "../../config.json" assert { type: "json" }; +import SupportedNetworks from "../../config.json"; import { EtherscanResponse, getEtherscanFeeResponse } from "./interface.js"; -export function printRequest(methodName: string, request: FastifyRequest, log: FastifyBaseLogger) { +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, entryPoint: string) { - 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 && chain["entryPoint"] == entryPoint }); +export function getNetworkConfig( + key: any, + supportedNetworks: any, + entryPoint: string +) { + 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 && chain["entryPoint"] == entryPoint; + }); } else - return SupportedNetworks.find((chain) => chain.chainId == key && chain.entryPoint == entryPoint); + return SupportedNetworks.find( + (chain) => chain.chainId == key && chain.entryPoint == entryPoint + ); } -export async function getSQLdata(apiKey: string, db: Database, log: FastifyBaseLogger) { +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); - }) - }) + 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); @@ -34,36 +54,55 @@ export async function getSQLdata(apiKey: string, db: Database, log: FastifyBaseL } } -export async function getEtherscanFee(chainId: number, log?: FastifyBaseLogger): Promise { +export async function getEtherscanFee( + chainId: number, + log?: FastifyBaseLogger +): Promise { try { const etherscanUrlsBase64 = process.env.ETHERSCAN_GAS_ORACLES; if (etherscanUrlsBase64) { - const buffer = Buffer.from(etherscanUrlsBase64, 'base64'); + const buffer = Buffer.from(etherscanUrlsBase64, "base64"); const etherscanUrls = JSON.parse(buffer.toString()); - console.log('etherscanUrl: ', etherscanUrls[chainId]); + console.log("etherscanUrl: ", etherscanUrls[chainId]); if (etherscanUrls[chainId]) { const data = await fetch(etherscanUrls[chainId]); const response: EtherscanResponse = await data.json(); - console.log('Etherscan Response: ', response); - if (response.result && typeof response.result === "object" && response.status === "1") { - console.log('setting maxFeePerGas and maxPriorityFeePerGas as received') - const maxFeePerGas = ethers.utils.parseUnits(response.result.suggestBaseFee, 'gwei') - const fastGasPrice = ethers.utils.parseUnits(response.result.FastGasPrice, 'gwei') + console.log("Etherscan Response: ", response); + if ( + response.result && + typeof response.result === "object" && + response.status === "1" + ) { + console.log( + "setting maxFeePerGas and maxPriorityFeePerGas as received" + ); + const maxFeePerGas = ethers.utils.parseUnits( + response.result.suggestBaseFee, + "gwei" + ); + const fastGasPrice = ethers.utils.parseUnits( + response.result.FastGasPrice, + "gwei" + ); return { maxPriorityFeePerGas: fastGasPrice.sub(maxFeePerGas), maxFeePerGas, gasPrice: maxFeePerGas, - } + }; } - if (response.result && typeof response.result === "string" && response.jsonrpc) { - const gasPrice = BigNumber.from(response.result) - console.log('setting gas price as received') + if ( + response.result && + typeof response.result === "string" && + response.jsonrpc + ) { + const gasPrice = BigNumber.from(response.result); + console.log("setting gas price as received"); return { maxFeePerGas: gasPrice, maxPriorityFeePerGas: gasPrice, - gasPrice: gasPrice - } + gasPrice: gasPrice, + }; } return null; } @@ -73,9 +112,8 @@ export async function getEtherscanFee(chainId: number, log?: FastifyBaseLogger): } catch (err) { if (log) { log.error(err); - log.info('fetching from provider'); + log.info("fetching from provider"); } return null; } } - diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 313eeda..0c9dcf3 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -11,7 +11,7 @@ "baseUrl": "src", "skipLibCheck": true, "strict": true, - "resolveJsonModule": true, + "resolveJsonModule": true }, "include": ["src/**/*.ts", "tests/**/*.ts"], "exclude": ["node_modules"] From 56a1dca1ed84d7cc0a43afdfe2de66fdada0c0dd Mon Sep 17 00:00:00 2001 From: Jineshdarjee Date: Mon, 17 Jun 2024 15:49:57 +0530 Subject: [PATCH 2/4] Reverted files --- .../src/constants/defaultNetworks.json | 531 ++++++++-------- backend/config.json.default | 292 +++++++++ backend/demo.env | 16 + backend/src/paymaster/index.ts | 576 +++++------------- 4 files changed, 735 insertions(+), 680 deletions(-) create mode 100644 backend/config.json.default create mode 100644 backend/demo.env diff --git a/admin_frontend/src/constants/defaultNetworks.json b/admin_frontend/src/constants/defaultNetworks.json index 8f927a8..7c6d48a 100644 --- a/admin_frontend/src/constants/defaultNetworks.json +++ b/admin_frontend/src/constants/defaultNetworks.json @@ -1,253 +1,282 @@ [ - { - "chainId": 1, - "bundler": "https://ethereum-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x7F690e93CecFca5A31E6e1dF50A33F6d3059048c" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 10, - "bundler": "https://optimism-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0x805650ce74561C85baA44a8Bd13E19633Fd0F79d" - }, - "thresholdValue": "21.8", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 14, - "bundler": "https://flare-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0x8A41594e5c6Fe492e437414c24eA6f401186b8d2" - }, - "thresholdValue": "1556", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 30, - "bundler": "https://rootstock-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26dD53b325bFFaACdFA224692EFF4C448C4" - }, - "thresholdValue": "0.00079", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 31, - "bundler": "https://testnet-rpc.etherspot.io/v1/31", - "contracts": { - "etherspotPaymasterAddress": "0xD302BE6e9D3fE0fBf8122a0C34611E31c0D0E792" - }, - "thresholdValue": "0.00079", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 56, - "bundler": "https://bnb-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0xEA5ecE95D3A28f9faB161779d20128b449F9EC9C" - }, - "thresholdValue": "0.09", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 97, - "bundler": "https://testnet-rpc.etherspot.io/v1/97", - "contracts": { - "etherspotPaymasterAddress": "0x153e26707DF3787183945B88121E4Eb188FDCAAA" - }, - "thresholdValue": "0.09", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 100, - "bundler": "https://gnosis-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x373aBcF1EA9e5802778E32870e7f72C8A6a90349" - }, - "thresholdValue": "50", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 114, - "bundler": "https://testnet-rpc.etherspot.io/v1/114", - "contracts": { - "etherspotPaymasterAddress": "0x2a18C360b525824B3e5656B5a705554f2a5036Be" - }, - "thresholdValue": "1556", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 122, - "bundler": "https://fuse-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0xEC2EE24E79C73DB13Dd9bC782856a5296626b7eb" - }, - "thresholdValue": "669" - }, - { - "chainId": 123, - "bundler": "https://testnet-rpc.etherspot.io/v1/123", - "contracts": { - "etherspotPaymasterAddress": "0xAF628C207513c5E51d894b3733056B8080634923" - }, - "thresholdValue": "669", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 137, - "bundler": "https://polygon-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0x26FeC24b0D467C9de105217B483931e8f944ff50" - }, - "thresholdValue": "69.85", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 5000, - "bundler": "https://mantle-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x8A41594e5c6Fe492e437414c24eA6f401186b8d2" - }, - "thresholdValue": "44.24", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 5003, - "bundler": "https://testnet-rpc.etherspot.io/v1/5003", - "contracts": { - "etherspotPaymasterAddress": "0x8350355c08aDAC387b443782124A30A8942BeC2e" - }, - "thresholdValue": "44.24", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 8217, - "bundler": "https://klaytn-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x4ebd86AAF89151b5303DB072e0205C668e31E5E7" - }, - "thresholdValue": "275.2", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 8453, - "bundler": "https://base-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" - }, - "thresholdValue": "15.19", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 42161, - "bundler": "https://arbitrum-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0xEC2EE24E79C73DB13Dd9bC782856a5296626b7eb" - }, - "thresholdValue": "43.10", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 43114, - "bundler": "https://avalanche-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x527569794781671319f20374A050BDbef4181aB3" - }, - "thresholdValue": "1.4", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 59144, - "bundler": "https://linea-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 84532, - "bundler": "https://testnet-rpc.etherspot.io/v1/84532", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" - }, - "thresholdValue": "15.19", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 421614, - "bundler": "https://testnet-rpc.etherspot.io/v1/421614", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" - }, - "thresholdValue": "43.10", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 534351, - "bundler": "https://testnet-rpc.etherspot.io/v1/534351", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 534352, - "bundler": "https://scroll-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 11155111, - "bundler": "https://testnet-rpc.etherspot.io/v1/11155111", - "contracts": { - "etherspotPaymasterAddress": "0xcaDBADcFeD5530A49762DFc9d1d712CcD6b09b25" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 28122024, - "bundler": "https://testnet-rpc.etherspot.io/v1/28122024", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "orochi" - }, - { - "chainId": 11155420, - "bundler": "https://testnet-rpc.etherspot.io/v1/11155420", - "contracts": { - "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" - }, - "thresholdValue": "21.8", - "MultiTokenPaymasterOracleUsed": "chainlink" - }, - { - "chainId": 888888888, - "bundler": "https://ancient8-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "orochi" - }, - { - "chainId": 80002, - "bundler": "https://testnet-rpc.etherspot.io/v1/80002", - "contracts": { - "etherspotPaymasterAddress": "0xe893a26dd53b325bffaacdfa224692eff4c448c4" - }, - "thresholdValue": "0.01", - "MultiTokenPaymasterOracleUsed": "chainlink" - } + { + "chainId": 1, + "bundler": "https://ethereum-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x7F690e93CecFca5A31E6e1dF50A33F6d3059048c" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 10, + "bundler": "https://optimism-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0x805650ce74561C85baA44a8Bd13E19633Fd0F79d" + }, + "thresholdValue": "21.8", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 14, + "bundler": "https://flare-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0x8A41594e5c6Fe492e437414c24eA6f401186b8d2" + }, + "thresholdValue": "1556", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 30, + "bundler": "https://rootstock-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26dD53b325bFFaACdFA224692EFF4C448C4" + }, + "thresholdValue": "0.00079", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 31, + "bundler": "https://testnet-rpc.etherspot.io/v1/31", + "contracts": { + "etherspotPaymasterAddress": "0xD302BE6e9D3fE0fBf8122a0C34611E31c0D0E792" + }, + "thresholdValue": "0.00079", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 56, + "bundler": "https://bnb-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0xEA5ecE95D3A28f9faB161779d20128b449F9EC9C" + }, + "thresholdValue": "0.09", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 97, + "bundler": "https://testnet-rpc.etherspot.io/v1/97", + "contracts": { + "etherspotPaymasterAddress": "0x153e26707DF3787183945B88121E4Eb188FDCAAA" + }, + "thresholdValue": "0.09", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 100, + "bundler": "https://gnosis-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x373aBcF1EA9e5802778E32870e7f72C8A6a90349" + }, + "thresholdValue": "50", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 114, + "bundler": "https://testnet-rpc.etherspot.io/v1/114", + "contracts": { + "etherspotPaymasterAddress": "0x2a18C360b525824B3e5656B5a705554f2a5036Be" + }, + "thresholdValue": "1556", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 122, + "bundler": "https://fuse-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0xEC2EE24E79C73DB13Dd9bC782856a5296626b7eb" + }, + "thresholdValue": "669", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 123, + "bundler": "https://testnet-rpc.etherspot.io/v1/123", + "contracts": { + "etherspotPaymasterAddress": "0xAF628C207513c5E51d894b3733056B8080634923" + }, + "thresholdValue": "669", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 137, + "bundler": "https://polygon-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0x26FeC24b0D467C9de105217B483931e8f944ff50" + }, + "thresholdValue": "69.85", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 5000, + "bundler": "https://mantle-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x8A41594e5c6Fe492e437414c24eA6f401186b8d2" + }, + "thresholdValue": "44.24", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 5003, + "bundler": "https://testnet-rpc.etherspot.io/v1/5003", + "contracts": { + "etherspotPaymasterAddress": "0x8350355c08aDAC387b443782124A30A8942BeC2e" + }, + "thresholdValue": "44.24", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 8217, + "bundler": "https://klaytn-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x4ebd86AAF89151b5303DB072e0205C668e31E5E7" + }, + "thresholdValue": "275.2", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 8453, + "bundler": "https://base-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" + }, + "thresholdValue": "15.19", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 42161, + "bundler": "https://arbitrum-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0xEC2EE24E79C73DB13Dd9bC782856a5296626b7eb" + }, + "thresholdValue": "43.10", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 43114, + "bundler": "https://avalanche-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x527569794781671319f20374A050BDbef4181aB3" + }, + "thresholdValue": "1.4", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 59144, + "bundler": "https://linea-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 84532, + "bundler": "https://testnet-rpc.etherspot.io/v1/84532", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" + }, + "thresholdValue": "15.19", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 421614, + "bundler": "https://testnet-rpc.etherspot.io/v1/421614", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" + }, + "thresholdValue": "43.10", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 534351, + "bundler": "https://testnet-rpc.etherspot.io/v1/534351", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 534352, + "bundler": "https://scroll-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 11155111, + "bundler": "https://testnet-rpc.etherspot.io/v1/11155111", + "contracts": { + "etherspotPaymasterAddress": "0xcaDBADcFeD5530A49762DFc9d1d712CcD6b09b25" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 28122024, + "bundler": "https://testnet-rpc.etherspot.io/v1/28122024", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "orochi", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 11155420, + "bundler": "https://testnet-rpc.etherspot.io/v1/11155420", + "contracts": { + "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" + }, + "thresholdValue": "21.8", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 888888888, + "bundler": "https://ancient8-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "orochi", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 80002, + "bundler": "https://testnet-rpc.etherspot.io/v1/80002", + "contracts": { + "etherspotPaymasterAddress": "0xe893a26dd53b325bffaacdfa224692eff4c448c4" + }, + "thresholdValue": "0.01", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + } ] diff --git a/backend/config.json.default b/backend/config.json.default new file mode 100644 index 0000000..d8ae092 --- /dev/null +++ b/backend/config.json.default @@ -0,0 +1,292 @@ +[ + { + "chainId": 1, + "bundler": "https://ethereum-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x7F690e93CecFca5A31E6e1dF50A33F6d3059048c" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 10, + "bundler": "https://optimism-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0x805650ce74561C85baA44a8Bd13E19633Fd0F79d" + }, + "thresholdValue": "21.8", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 14, + "bundler": "https://flare-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0x8A41594e5c6Fe492e437414c24eA6f401186b8d2" + }, + "thresholdValue": "1556", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 30, + "bundler": "https://rootstock-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26dD53b325bFFaACdFA224692EFF4C448C4" + }, + "thresholdValue": "0.00079", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 31, + "bundler": "https://testnet-rpc.etherspot.io/v1/31", + "contracts": { + "etherspotPaymasterAddress": "0xD302BE6e9D3fE0fBf8122a0C34611E31c0D0E792" + }, + "thresholdValue": "0.00079", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 56, + "bundler": "https://bnb-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0xEA5ecE95D3A28f9faB161779d20128b449F9EC9C" + }, + "thresholdValue": "0.09", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 97, + "bundler": "https://testnet-rpc.etherspot.io/v1/97", + "contracts": { + "etherspotPaymasterAddress": "0x153e26707DF3787183945B88121E4Eb188FDCAAA" + }, + "thresholdValue": "0.09", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 100, + "bundler": "https://gnosis-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x373aBcF1EA9e5802778E32870e7f72C8A6a90349" + }, + "thresholdValue": "50", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 114, + "bundler": "https://testnet-rpc.etherspot.io/v1/114", + "contracts": { + "etherspotPaymasterAddress": "0x2a18C360b525824B3e5656B5a705554f2a5036Be" + }, + "thresholdValue": "1556", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 122, + "bundler": "https://fuse-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0xEC2EE24E79C73DB13Dd9bC782856a5296626b7eb" + }, + "thresholdValue": "669", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 123, + "bundler": "https://testnet-rpc.etherspot.io/v1/123", + "contracts": { + "etherspotPaymasterAddress": "0xAF628C207513c5E51d894b3733056B8080634923" + }, + "thresholdValue": "669", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 137, + "bundler": "https://polygon-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0x26FeC24b0D467C9de105217B483931e8f944ff50" + }, + "thresholdValue": "69.85", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 5000, + "bundler": "https://mantle-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x8A41594e5c6Fe492e437414c24eA6f401186b8d2" + }, + "thresholdValue": "44.24", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 5003, + "bundler": "https://testnet-rpc.etherspot.io/v1/5003", + "contracts": { + "etherspotPaymasterAddress": "0x8350355c08aDAC387b443782124A30A8942BeC2e" + }, + "thresholdValue": "44.24", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 8217, + "bundler": "https://klaytn-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x4ebd86AAF89151b5303DB072e0205C668e31E5E7" + }, + "thresholdValue": "275.2", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 8453, + "bundler": "https://base-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" + }, + "thresholdValue": "15.19", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 42161, + "bundler": "https://arbitrum-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0xEC2EE24E79C73DB13Dd9bC782856a5296626b7eb" + }, + "thresholdValue": "43.10", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 43114, + "bundler": "https://avalanche-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x527569794781671319f20374A050BDbef4181aB3" + }, + "thresholdValue": "1.4", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 59144, + "bundler": "https://linea-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 84532, + "bundler": "https://testnet-rpc.etherspot.io/v1/84532", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" + }, + "thresholdValue": "15.19", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 421614, + "bundler": "https://testnet-rpc.etherspot.io/v1/421614", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" + }, + "thresholdValue": "43.10", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 534351, + "bundler": "https://testnet-rpc.etherspot.io/v1/534351", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 534352, + "bundler": "https://scroll-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 11155111, + "bundler": "https://testnet-rpc.etherspot.io/v1/11155111", + "contracts": { + "etherspotPaymasterAddress": "0xcaDBADcFeD5530A49762DFc9d1d712CcD6b09b25" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 28122024, + "bundler": "https://testnet-rpc.etherspot.io/v1/28122024", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "orochi", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 11155420, + "bundler": "https://testnet-rpc.etherspot.io/v1/11155420", + "contracts": { + "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" + }, + "thresholdValue": "21.8", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 888888888, + "bundler": "https://ancient8-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "orochi", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 80002, + "bundler": "https://testnet-rpc.etherspot.io/v1/80002", + "contracts": { + "etherspotPaymasterAddress": "0xe893a26dd53b325bffaacdfa224692eff4c448c4" + }, + "thresholdValue": "0.01", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 80002, + "bundler": "https://testnet-rpc.etherspot.io/v2/80002", + "contracts": { + "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" + }, + "thresholdValue": "0.01", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x0000000071727De22E5E9d8BAf0edAc6f37da032" + } +] diff --git a/backend/demo.env b/backend/demo.env new file mode 100644 index 0000000..f78986c --- /dev/null +++ b/backend/demo.env @@ -0,0 +1,16 @@ +NODE_ENV=development +LOG_LEVEL=debug +UNSAFE_MODE=false + +API_HOST=127.0.0.1 +API_PORT=5050 + +STACKUP_API_KEY= +SUPPORTED_NETWORKS= +ADMIN_WALLET_ADDRESS= +DEFAULT_INDEXER_ENDPOINT=http://localhost:3003 +FEE_MARKUP= +MULTI_TOKEN_MARKUP=1150000 +ETHERSCAN_GAS_ORACLES= +DEFAULT_API_KEY= +WEBHOOK_URL= diff --git a/backend/src/paymaster/index.ts b/backend/src/paymaster/index.ts index 7644edf..92e7ac4 100644 --- a/backend/src/paymaster/index.ts +++ b/backend/src/paymaster/index.ts @@ -1,69 +1,40 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { - providers, - Wallet, - ethers, - Contract, - BigNumber, - BigNumberish, - utils, -} from "ethers"; -import { - arrayify, - BytesLike, - defaultAbiCoder, - hexConcat, - hexZeroPad, -} from "ethers/lib/utils.js"; -import { FastifyBaseLogger } from "fastify"; -import EtherspotAbiV06 from "../abi/EtherspotAbi.js"; +import { providers, Wallet, ethers, Contract, BigNumber, BigNumberish, utils } from 'ethers'; +import { arrayify, BytesLike, defaultAbiCoder, hexConcat, hexZeroPad } from 'ethers/lib/utils.js'; +import { FastifyBaseLogger } from 'fastify'; +import EtherspotAbiV06 from '../abi/EtherspotAbi.js'; import EtherspotAbiV07 from "../abi/EtherspotVerifyingSignerAbi.js"; -import { PimlicoPaymaster } from "./pimlico.js"; -import ErrorMessage from "../constants/ErrorMessage.js"; -import { PAYMASTER_ADDRESS } from "../constants/Pimlico.js"; -import { getEtherscanFee } from "../utils/common.js"; -import MultiTokenPaymasterAbi from "../abi/MultiTokenPaymasterAbi.js"; -import OrochiOracleAbi from "../abi/OrochiOracleAbi.js"; -import ChainlinkOracleAbi from "../abi/ChainlinkOracleAbi.js"; +import { PimlicoPaymaster } from './pimlico.js'; +import ErrorMessage from '../constants/ErrorMessage.js'; +import { PAYMASTER_ADDRESS } from '../constants/Pimlico.js'; +import { getEtherscanFee } from '../utils/common.js'; +import MultiTokenPaymasterAbi from '../abi/MultiTokenPaymasterAbi.js'; +import OrochiOracleAbi from '../abi/OrochiOracleAbi.js'; +import ChainlinkOracleAbi from '../abi/ChainlinkOracleAbi.js'; export class Paymaster { feeMarkUp: BigNumber; multiTokenMarkUp: Number; constructor(feeMarkUp: string, multiTokenMarkUp: string) { - this.feeMarkUp = ethers.utils.parseUnits(feeMarkUp, "gwei"); - if (isNaN(Number(multiTokenMarkUp))) - this.multiTokenMarkUp = 1150000; // 15% more of the actual cost. Can be anything between 1e6 to 2e6 + this.feeMarkUp = ethers.utils.parseUnits(feeMarkUp, 'gwei'); + if (isNaN(Number(multiTokenMarkUp))) this.multiTokenMarkUp = 1150000 // 15% more of the actual cost. Can be anything between 1e6 to 2e6 else this.multiTokenMarkUp = Number(multiTokenMarkUp); } - packUint(high128: BigNumberish, low128: BigNumberish): string { - return hexZeroPad( - BigNumber.from(high128).shl(128).add(low128).toHexString(), - 32 - ); + packUint (high128: BigNumberish, low128: BigNumberish): string { + return hexZeroPad(BigNumber.from(high128).shl(128).add(low128).toHexString(), 32) } - packPaymasterData( - paymaster: string, - paymasterVerificationGasLimit: BigNumberish, - postOpGasLimit: BigNumberish, - paymasterData?: BytesLike - ): BytesLike { + packPaymasterData (paymaster: string, paymasterVerificationGasLimit: BigNumberish, postOpGasLimit: BigNumberish, paymasterData?: BytesLike): BytesLike { return ethers.utils.hexConcat([ paymaster, this.packUint(paymasterVerificationGasLimit, postOpGasLimit), - paymasterData ?? "0x", - ]); + paymasterData ?? '0x' + ]) } - async getPaymasterData( - userOp: any, - validUntil: string, - validAfter: string, - paymasterContract: Contract, - signer: Wallet - ) { + async getPaymasterData(userOp: any, validUntil: string, validAfter: string, paymasterContract: Contract, signer: Wallet) { // actual signing... const hash = await paymasterContract.getHash( userOp, @@ -74,52 +45,32 @@ export class Paymaster { const sig = await signer.signMessage(arrayify(hash)); const paymasterData = hexConcat([ - defaultAbiCoder.encode(["uint48", "uint48"], [validUntil, validAfter]), + defaultAbiCoder.encode( + ['uint48', 'uint48'], + [validUntil, validAfter] + ), sig, ]); return paymasterData; } - async signV07( - userOp: any, - validUntil: string, - validAfter: string, - entryPoint: string, - paymasterAddress: string, - bundlerRpc: string, - signer: Wallet, - estimate: boolean, - log?: FastifyBaseLogger - ) { + async signV07(userOp: any, validUntil: string, validAfter: string, entryPoint: string, paymasterAddress: string, + bundlerRpc: string, signer: Wallet, estimate: boolean, log?: FastifyBaseLogger) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const paymasterContract = new ethers.Contract( - paymasterAddress, - EtherspotAbiV07, - provider - ); - if (!userOp.signature) userOp.signature = "0x"; - if (userOp.factory && userOp.factoryData) - userOp.initCode = hexConcat([userOp.factory, userOp.factoryData ?? ""]); + const paymasterContract = new ethers.Contract(paymasterAddress, EtherspotAbiV07, provider); + if (!userOp.signature) userOp.signature = '0x'; + if (userOp.factory && userOp.factoryData) userOp.initCode = hexConcat([userOp.factory, userOp.factoryData ?? '']) if (!userOp.initCode) userOp.initCode = "0x"; if (estimate) { - const response = await provider.send("eth_estimateUserOperationGas", [ - userOp, - entryPoint, - ]); + const response = await provider.send('eth_estimateUserOperationGas', [userOp, entryPoint]); userOp.verificationGasLimit = response.verificationGasLimit; userOp.callGasLimit = response.callGasLimit; userOp.preVerificationGas = response.preVerificationGas; } - const accountGasLimits = this.packUint( - userOp.verificationGasLimit, - userOp.callGasLimit - ); - const gasFees = this.packUint( - userOp.maxPriorityFeePerGas, - userOp.maxFeePerGas - ); + const accountGasLimits = this.packUint(userOp.verificationGasLimit, userOp.callGasLimit) + const gasFees = this.packUint(userOp.maxPriorityFeePerGas, userOp.maxFeePerGas); let packedUserOp = { sender: userOp.sender, nonce: userOp.nonce, @@ -128,21 +79,11 @@ export class Paymaster { accountGasLimits: accountGasLimits, preVerificationGas: userOp.preVerificationGas, gasFees: gasFees, - paymasterAndData: this.packPaymasterData( - paymasterAddress, - BigNumber.from(30000), - "0x1" - ), - signature: userOp.signature, - }; + paymasterAndData: this.packPaymasterData(paymasterAddress, BigNumber.from(30000), "0x1"), + signature: userOp.signature + } - let paymasterData = await this.getPaymasterData( - packedUserOp, - validUntil, - validAfter, - paymasterContract, - signer - ); + let paymasterData = await this.getPaymasterData(packedUserOp, validUntil, validAfter, paymasterContract, signer); let returnValue; if (estimate) { returnValue = { @@ -152,32 +93,23 @@ export class Paymaster { verificationGasLimit: userOp.verificationGasLimit, callGasLimit: userOp.callGasLimit, paymasterVerificationGasLimit: BigNumber.from(30000).toString(), - paymasterPostOpGasLimit: "0x1", - }; + paymasterPostOpGasLimit: "0x1" + } } else { returnValue = { paymaster: paymasterAddress, paymasterData: paymasterData, - }; + } } return returnValue; } catch (err: any) { - if (log) log.error(err, "signv07"); - throw new Error( - "Failed to process request to bundler. Please contact support team RawErrorMsg:" + - err.message - ); + if (log) log.error(err, 'signv07'); + throw new Error('Failed to process request to bundler. Please contact support team RawErrorMsg:' + err.message) } } - async getPaymasterAndData( - userOp: any, - validUntil: string, - validAfter: string, - paymasterContract: Contract, - signer: Wallet - ) { + async getPaymasterAndData(userOp: any, validUntil: string, validAfter: string, paymasterContract: Contract, signer: Wallet) { // actual signing... const hash = await paymasterContract.getHash( userOp, @@ -189,55 +121,30 @@ export class Paymaster { const paymasterAndData = hexConcat([ paymasterContract.address, - defaultAbiCoder.encode(["uint48", "uint48"], [validUntil, validAfter]), + defaultAbiCoder.encode( + ['uint48', 'uint48'], + [validUntil, validAfter] + ), sig, ]); return paymasterAndData; } - async signV06( - userOp: any, - validUntil: string, - validAfter: string, - entryPoint: string, - paymasterAddress: string, - bundlerRpc: string, - signer: Wallet, - estimate: boolean, - log?: FastifyBaseLogger - ) { + async signV06(userOp: any, validUntil: string, validAfter: string, entryPoint: string, paymasterAddress: string, + bundlerRpc: string, signer: Wallet, estimate: boolean, log?: FastifyBaseLogger) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const paymasterContract = new ethers.Contract( - paymasterAddress, - EtherspotAbiV06, - provider - ); - userOp.paymasterAndData = await this.getPaymasterAndData( - userOp, - validUntil, - validAfter, - paymasterContract, - signer - ); - if (!userOp.signature) userOp.signature = "0x"; + const paymasterContract = new ethers.Contract(paymasterAddress, EtherspotAbiV06, provider); + userOp.paymasterAndData = await this.getPaymasterAndData(userOp, validUntil, validAfter, paymasterContract, signer); + if (!userOp.signature) userOp.signature = '0x'; if (estimate) { - const response = await provider.send("eth_estimateUserOperationGas", [ - userOp, - entryPoint, - ]); + const response = await provider.send('eth_estimateUserOperationGas', [userOp, entryPoint]); userOp.verificationGasLimit = response.verificationGasLimit; userOp.preVerificationGas = response.preVerificationGas; userOp.callGasLimit = response.callGasLimit; } - const paymasterAndData = await this.getPaymasterAndData( - userOp, - validUntil, - validAfter, - paymasterContract, - signer - ); + const paymasterAndData = await this.getPaymasterAndData(userOp, validUntil, validAfter, paymasterContract, signer); let returnValue; if (estimate) { returnValue = { @@ -245,32 +152,22 @@ export class Paymaster { verificationGasLimit: userOp.verificationGasLimit, preVerificationGas: userOp.preVerificationGas, callGasLimit: userOp.callGasLimit, - }; + } } else { returnValue = { - paymasterAndData, - }; + paymasterAndData + } } return returnValue; } catch (err: any) { - if (log) log.error(err, "signV06"); - throw new Error( - "Failed to process request to bundler. Please contact support team RawErrorMsg:" + - err.message - ); + if (log) log.error(err, 'signV06'); + throw new Error('Failed to process request to bundler. Please contact support team RawErrorMsg:' + err.message) } - } + } - async getPaymasterAndDataForMultiTokenPaymaster( - userOp: any, - validUntil: string, - validAfter: string, - feeToken: string, - ethPrice: string, - paymasterContract: Contract, - signer: Wallet - ) { + async getPaymasterAndDataForMultiTokenPaymaster(userOp: any, validUntil: string, validAfter: string, feeToken: string, + ethPrice: string, paymasterContract: Contract, signer: Wallet) { const exchangeRate = 1000000; // This is for setting min tokens required for the txn that gets validated on estimate const rate = ethers.BigNumber.from(exchangeRate).mul(ethPrice); const priceMarkup = this.multiTokenMarkUp; @@ -284,24 +181,17 @@ export class Paymaster { feeToken, ethers.constants.AddressZero, rate.toNumber().toFixed(0), - priceMarkup + priceMarkup, ); const sig = await signer.signMessage(arrayify(hash)); const paymasterAndData = hexConcat([ paymasterContract.address, - "0x00", + '0x00', defaultAbiCoder.encode( - ["uint48", "uint48", "address", "address", "uint256", "uint32"], - [ - validUntil, - validAfter, - feeToken, - ethers.constants.AddressZero, - rate.toNumber().toFixed(0), - priceMarkup, - ] + ['uint48', 'uint48', 'address', 'address', 'uint256', 'uint32'], + [validUntil, validAfter, feeToken, ethers.constants.AddressZero, rate.toNumber().toFixed(0), priceMarkup] ), sig, ]); @@ -309,108 +199,50 @@ export class Paymaster { return paymasterAndData; } - async signMultiTokenPaymaster( - userOp: any, - validUntil: string, - validAfter: string, - entryPoint: string, - paymasterAddress: string, - feeToken: string, - oracleAggregator: string, - bundlerRpc: string, - signer: Wallet, - oracleName: string, - log?: FastifyBaseLogger - ) { + async signMultiTokenPaymaster(userOp: any, validUntil: string, validAfter: string, entryPoint: string, paymasterAddress: string, + feeToken: string, oracleAggregator: string, bundlerRpc: string, signer: Wallet, oracleName: string, log?: FastifyBaseLogger) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const paymasterContract = new ethers.Contract( - paymasterAddress, - MultiTokenPaymasterAbi, - provider - ); + const paymasterContract = new ethers.Contract(paymasterAddress, MultiTokenPaymasterAbi, provider); let ethPrice = ""; if (oracleName === "orochi") { - const oracleContract = new ethers.Contract( - oracleAggregator, - OrochiOracleAbi, - provider - ); - const result = await oracleContract.getLatestData( - 1, - ethers.utils.hexlify(ethers.utils.toUtf8Bytes("ETH")).padEnd(42, "0") - ); + const oracleContract = new ethers.Contract(oracleAggregator, OrochiOracleAbi, provider); + const result = await oracleContract.getLatestData(1, ethers.utils.hexlify(ethers.utils.toUtf8Bytes('ETH')).padEnd(42, '0')) ethPrice = Number(ethers.utils.formatEther(result)).toFixed(0); } else { - const chainlinkContract = new ethers.Contract( - oracleAggregator, - ChainlinkOracleAbi, - provider - ); + const chainlinkContract = new ethers.Contract(oracleAggregator, ChainlinkOracleAbi, provider); const decimals = await chainlinkContract.decimals(); const result = await chainlinkContract.latestAnswer(); - ethPrice = Number(ethers.utils.formatUnits(result, decimals)).toFixed( - 0 - ); + ethPrice = Number(ethers.utils.formatUnits(result, decimals)).toFixed(0); } - userOp.paymasterAndData = - await this.getPaymasterAndDataForMultiTokenPaymaster( - userOp, - validUntil, - validAfter, - feeToken, - ethPrice, - paymasterContract, - signer - ); - - if (!userOp.signature) userOp.signature = "0x"; - const response = await provider.send("eth_estimateUserOperationGas", [ - userOp, - entryPoint, - ]); + userOp.paymasterAndData = await this.getPaymasterAndDataForMultiTokenPaymaster(userOp, validUntil, validAfter, feeToken, ethPrice, paymasterContract, signer); + + if (!userOp.signature) userOp.signature = '0x'; + const response = await provider.send('eth_estimateUserOperationGas', [userOp, entryPoint]); userOp.verificationGasLimit = response.verificationGasLimit; userOp.preVerificationGas = response.preVerificationGas; userOp.callGasLimit = response.callGasLimit; - const paymasterAndData = - await this.getPaymasterAndDataForMultiTokenPaymaster( - userOp, - validUntil, - validAfter, - feeToken, - ethPrice, - paymasterContract, - signer - ); + const paymasterAndData = await this.getPaymasterAndDataForMultiTokenPaymaster(userOp, validUntil, validAfter, feeToken, ethPrice, paymasterContract, signer); const returnValue = { paymasterAndData, verificationGasLimit: response.verificationGasLimit, preVerificationGas: response.preVerificationGas, callGasLimit: response.callGasLimit, - }; + } return returnValue; } catch (err: any) { - if (log) log.error(err, "signCombinedPaymaster"); - throw new Error( - "Failed to process request to bundler. Please contact support team RawErrorMsg:" + - err.message - ); + if (log) log.error(err, 'signCombinedPaymaster'); + throw new Error('Failed to process request to bundler. Please contact support team RawErrorMsg:' + err.message) } } - async pimlico( - userOp: any, - bundlerRpc: string, - entryPoint: string, - PaymasterAddress: string, - log?: FastifyBaseLogger - ) { + async pimlico(userOp: any, bundlerRpc: string, entryPoint: string, PaymasterAddress: string, log?: FastifyBaseLogger) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const erc20Paymaster = new PimlicoPaymaster(PaymasterAddress, provider); - if (!userOp.signature) userOp.signature = "0x"; + const erc20Paymaster = new PimlicoPaymaster(PaymasterAddress, provider) + if (!userOp.signature) userOp.signature = '0x'; // The minimum ABI to get the ERC20 Token balance const minABI = [ @@ -418,46 +250,27 @@ export class Paymaster { { constant: true, - inputs: [{ name: "_owner", type: "address" }], + inputs: [{ name: '_owner', type: 'address' }], - name: "balanceOf", + name: 'balanceOf', - outputs: [{ name: "balance", type: "uint256" }], + outputs: [{ name: 'balance', type: 'uint256' }], - type: "function", + type: 'function', }, - ]; - const tokenAmountRequired = await erc20Paymaster.calculateTokenAmount( - userOp - ); - const tokenContract = new Contract( - await erc20Paymaster.tokenAddress, - minABI, - provider - ); + ] + 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}` - ); + 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 - ); + 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(); + const response = await provider.send('eth_estimateUserOperationGas', [userOp, entryPoint]); + userOp.verificationGasLimit = ethers.BigNumber.from(response.verificationGasLimit).add(100000).toString(); userOp.preVerificationGas = response.preVerificationGas; userOp.callGasLimit = response.callGasLimit; paymasterAndData = await erc20Paymaster.generatePaymasterAndData(userOp); @@ -469,62 +282,35 @@ export class Paymaster { callGasLimit: response.callGasLimit, }; } catch (err: any) { - if (err.message.includes("The required token amount")) - throw new Error(err.message); - if (log) log.error(err, "pimlico"); - throw new Error( - "Failed to process request to bundler. Please contact support team RawErrorMsg: " + - err.message - ); + if (err.message.includes('The required token amount')) throw new Error(err.message); + if (log) log.error(err, 'pimlico'); + throw new Error('Failed to process request to bundler. Please contact support team RawErrorMsg: ' + err.message) } } - async pimlicoAddress( - gasToken: string, - chainId: number, - log?: FastifyBaseLogger - ) { + async pimlicoAddress(gasToken: string, chainId: number, log?: FastifyBaseLogger) { try { return { - message: - PAYMASTER_ADDRESS[chainId][gasToken] ?? - "Requested Token Paymaster is not available/deployed", - }; + message: PAYMASTER_ADDRESS[chainId][gasToken] ?? 'Requested Token Paymaster is not available/deployed', + } } catch (err: any) { - if (log) log.error(err, "pimlicoAddress"); - throw new Error(err.message); + if (log) log.error(err, 'pimlicoAddress'); + throw new Error(err.message) } } - async whitelistAddresses( - address: string[], - paymasterAddress: string, - bundlerRpc: string, - relayerKey: string, - chainId: number, - log?: FastifyBaseLogger - ) { + async whitelistAddresses(address: string[], paymasterAddress: string, bundlerRpc: string, relayerKey: string, chainId: number, log?: FastifyBaseLogger) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const paymasterContract = new ethers.Contract( - paymasterAddress, - EtherspotAbiV06, - provider - ); - const signer = new Wallet(relayerKey, provider); + const paymasterContract = new ethers.Contract(paymasterAddress, EtherspotAbiV06, provider); + const signer = new Wallet(relayerKey, provider) for (let i = 0; i < address.length; i++) { - const isAdded = await paymasterContract.check( - signer.address, - address[i] - ); + const isAdded = await paymasterContract.check(signer.address, address[i]); if (isAdded) { - throw new Error(`${address[i]} already whitelisted`); + throw new Error(`${address[i]} already whitelisted`) } } - const encodedData = paymasterContract.interface.encodeFunctionData( - "addBatchToWhitelist", - [address] - ); + const encodedData = paymasterContract.interface.encodeFunctionData('addBatchToWhitelist', [address]); const etherscanFeeData = await getEtherscanFee(chainId); let feeData; @@ -532,15 +318,9 @@ export class Paymaster { feeData = etherscanFeeData; } else { feeData = await provider.getFeeData(); - feeData.gasPrice = feeData.gasPrice - ? feeData.gasPrice.add(this.feeMarkUp) - : null; - feeData.maxFeePerGas = feeData.maxFeePerGas - ? feeData.maxFeePerGas.add(this.feeMarkUp) - : null; - feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas - ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) - : null; + feeData.gasPrice = feeData.gasPrice ? feeData.gasPrice.add(this.feeMarkUp) : null; + feeData.maxFeePerGas = feeData.maxFeePerGas ? feeData.maxFeePerGas.add(this.feeMarkUp) : null; + feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) : null; } let tx: providers.TransactionResponse; @@ -549,7 +329,7 @@ export class Paymaster { to: paymasterAddress, data: encodedData, gasPrice: feeData.gasPrice ?? undefined, - }); + }) } else { tx = await signer.sendTransaction({ to: paymasterAddress, @@ -563,63 +343,37 @@ export class Paymaster { // await tx.wait(); return { - message: `Successfully whitelisted with transaction Hash ${tx.hash}`, + message: `Successfully whitelisted with transaction Hash ${tx.hash}` }; } catch (err: any) { - if (err.message.includes("already whitelisted")) - throw new Error(err.message); - if (log) log.error(err, "whitelistAddresses"); - throw new Error( - ErrorMessage.ERROR_ON_SUBMITTING_TXN + ` RawErrorMsg: ${err.message}` - ); + if (err.message.includes('already whitelisted')) throw new Error(err.message); + if (log) log.error(err, 'whitelistAddresses') + throw new Error(ErrorMessage.ERROR_ON_SUBMITTING_TXN + ` RawErrorMsg: ${err.message}`); } } - async removeWhitelistAddress( - address: string[], - paymasterAddress: string, - bundlerRpc: string, - relayerKey: string, - chainId: number, - log?: FastifyBaseLogger - ) { + async removeWhitelistAddress(address: string[], paymasterAddress: string, bundlerRpc: string, relayerKey: string, chainId: number, log?: FastifyBaseLogger) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const paymasterContract = new ethers.Contract( - paymasterAddress, - EtherspotAbiV06, - provider - ); - const signer = new Wallet(relayerKey, provider); + const paymasterContract = new ethers.Contract(paymasterAddress, EtherspotAbiV06, provider); + const signer = new Wallet(relayerKey, provider) for (let i = 0; i < address.length; i++) { - const isAdded = await paymasterContract.check( - signer.address, - address[i] - ); + const isAdded = await paymasterContract.check(signer.address, address[i]); if (!isAdded) { - throw new Error(`${address[i]} is not whitelisted`); + throw new Error(`${address[i]} is not whitelisted`) } } - const encodedData = paymasterContract.interface.encodeFunctionData( - "removeBatchFromWhitelist", - [address] - ); + const encodedData = paymasterContract.interface.encodeFunctionData('removeBatchFromWhitelist', [address]); const etherscanFeeData = await getEtherscanFee(chainId); let feeData; if (etherscanFeeData) { feeData = etherscanFeeData; } else { feeData = await provider.getFeeData(); - feeData.gasPrice = feeData.gasPrice - ? feeData.gasPrice.add(this.feeMarkUp) - : null; - feeData.maxFeePerGas = feeData.maxFeePerGas - ? feeData.maxFeePerGas.add(this.feeMarkUp) - : null; - feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas - ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) - : null; + feeData.gasPrice = feeData.gasPrice ? feeData.gasPrice.add(this.feeMarkUp) : null; + feeData.maxFeePerGas = feeData.maxFeePerGas ? feeData.maxFeePerGas.add(this.feeMarkUp) : null; + feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) : null; } let tx: providers.TransactionResponse; @@ -628,7 +382,7 @@ export class Paymaster { to: paymasterAddress, data: encodedData, gasPrice: feeData.gasPrice ?? undefined, - }); + }) } else { tx = await signer.sendTransaction({ to: paymasterAddress, @@ -642,82 +396,49 @@ export class Paymaster { // await tx.wait(); return { - message: `Successfully removed whitelisted addresses with transaction Hash ${tx.hash}`, + message: `Successfully removed whitelisted addresses with transaction Hash ${tx.hash}` }; } catch (err: any) { - if (err.message.includes("is not whitelisted")) - throw new Error(err.message); - if (log) log.error(err, "removeWhitelistAddress"); + if (err.message.includes('is not whitelisted')) throw new Error(err.message); + if (log) log.error(err, 'removeWhitelistAddress'); throw new Error(ErrorMessage.ERROR_ON_SUBMITTING_TXN); } } - async checkWhitelistAddress( - accountAddress: string, - paymasterAddress: string, - bundlerRpc: string, - relayerKey: string, - log?: FastifyBaseLogger - ) { + async checkWhitelistAddress(accountAddress: string, paymasterAddress: string, bundlerRpc: string, relayerKey: string, log?: FastifyBaseLogger) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const signer = new Wallet(relayerKey, provider); - const paymasterContract = new ethers.Contract( - paymasterAddress, - EtherspotAbiV06, - provider - ); + const signer = new Wallet(relayerKey, provider) + const paymasterContract = new ethers.Contract(paymasterAddress, EtherspotAbiV06, provider); return paymasterContract.check(signer.address, accountAddress); } catch (err) { - if (log) log.error(err, "checkWhitelistAddress"); + if (log) log.error(err, 'checkWhitelistAddress'); throw new Error(ErrorMessage.RPC_ERROR); } } - async deposit( - amount: string, - paymasterAddress: string, - bundlerRpc: string, - relayerKey: string, - chainId: number, - log?: FastifyBaseLogger - ) { + async deposit(amount: string, paymasterAddress: string, bundlerRpc: string, relayerKey: string, chainId: number, isEpv06: boolean, log?: FastifyBaseLogger) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); - const paymasterContract = new ethers.Contract( - paymasterAddress, - EtherspotAbiV06, - provider - ); - const signer = new Wallet(relayerKey, provider); + const paymasterContract = new ethers.Contract(paymasterAddress, isEpv06 ? EtherspotAbiV06 : EtherspotAbiV07, provider); + const signer = new Wallet(relayerKey, provider) const balance = await signer.getBalance(); const amountInWei = ethers.utils.parseEther(amount.toString()); if (amountInWei.gte(balance)) - throw new Error( - `${signer.address} Balance is less than the amount to be deposited` - ); + throw new Error(`${signer.address} Balance is less than the amount to be deposited`) - const encodedData = paymasterContract.interface.encodeFunctionData( - "depositFunds", - [] - ); + const encodedData = paymasterContract.interface.encodeFunctionData(isEpv06 ? 'depositFunds': 'deposit', []); const etherscanFeeData = await getEtherscanFee(chainId); - console.log("etherscanFeeData: ", etherscanFeeData); + console.log('etherscanFeeData: ', etherscanFeeData); let feeData; if (etherscanFeeData) { feeData = etherscanFeeData; } else { feeData = await provider.getFeeData(); - feeData.gasPrice = feeData.gasPrice - ? feeData.gasPrice.add(this.feeMarkUp) - : null; - feeData.maxFeePerGas = feeData.maxFeePerGas - ? feeData.maxFeePerGas.add(this.feeMarkUp) - : null; - feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas - ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) - : null; + feeData.gasPrice = feeData.gasPrice ? feeData.gasPrice.add(this.feeMarkUp) : null; + feeData.maxFeePerGas = feeData.maxFeePerGas ? feeData.maxFeePerGas.add(this.feeMarkUp) : null; + feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ? feeData.maxPriorityFeePerGas.add(this.feeMarkUp) : null; } let tx: providers.TransactionResponse; @@ -727,7 +448,7 @@ export class Paymaster { data: encodedData, value: amountInWei, gasPrice: feeData.gasPrice ?? undefined, - }); + }) } else { tx = await signer.sendTransaction({ to: paymasterAddress, @@ -739,17 +460,14 @@ export class Paymaster { }); } // commented the below line to avoid timeouts for long delays in transaction confirmation. - // await tx.wait(); + // await tx.wait(); return { - message: `Successfully deposited with transaction Hash ${tx.hash}`, + message: `Successfully deposited with transaction Hash ${tx.hash}` }; } catch (err: any) { - if (log) log.error(err, "deposit"); - if ( - err.message.includes("Balance is less than the amount to be deposited") - ) - throw new Error(err.message); + if (log) log.error(err, 'deposit'); + 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); } } From 49c72752eca2959c296c51207fda749877543320 Mon Sep 17 00:00:00 2001 From: Jineshdarjee Date: Tue, 18 Jun 2024 15:16:56 +0530 Subject: [PATCH 3/4] Reverted file --- backend/src/routes/index.ts | 1289 ++++++++++++++++++++++------------- 1 file changed, 829 insertions(+), 460 deletions(-) diff --git a/backend/src/routes/index.ts b/backend/src/routes/index.ts index 824358f..eeb84e6 100644 --- a/backend/src/routes/index.ts +++ b/backend/src/routes/index.ts @@ -3,7 +3,10 @@ import { Type } from "@sinclair/typebox"; import { FastifyPluginAsync } from "fastify"; import { BigNumber, Wallet, ethers, providers } from "ethers"; import { gql, request as GLRequest } from "graphql-request"; -import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager"; +import { + GetSecretValueCommand, + SecretsManagerClient, +} from "@aws-sdk/client-secrets-manager"; import { Paymaster } from "../paymaster/index.js"; import SupportedNetworks from "../../config.json" assert { type: "json" }; import { PAYMASTER_ADDRESS } from "../constants/Pimlico.js"; @@ -13,14 +16,17 @@ import { decode } from "../utils/crypto.js"; import { printRequest, getNetworkConfig, getSQLdata } from "../utils/common.js"; const SUPPORTED_ENTRYPOINTS = { - 'EPV_06' : "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", - 'EPV_07' : "0x0000000071727De22E5E9d8BAf0edAc6f37da032" -} + EPV_06: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + EPV_07: "0x0000000071727De22E5E9d8BAf0edAc6f37da032", +}; const routes: FastifyPluginAsync = async (server) => { - const paymaster = new Paymaster(server.config.FEE_MARKUP, server.config.MULTI_TOKEN_MARKUP); + const paymaster = new Paymaster( + server.config.FEE_MARKUP, + server.config.MULTI_TOKEN_MARKUP + ); - const prefixSecretId = 'arka_'; + const prefixSecretId = "arka_"; let client: SecretsManagerClient; @@ -39,232 +45,359 @@ const routes: FastifyPluginAsync = async (server) => { 400: Type.Object({ error: Type.String(), }), - } - } - } + }, + }, + }; - server.post( - "/", - async function (request, reply) { - try { - printRequest("/", request, server.log); - const query: any = request.query; - const body: any = request.body; - if (!body) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.EMPTY_BODY }); - const userOp = body.params[0]; - const entryPoint = body.params[1]; - let context = body.params[2]; - let gasToken = context?.token ? context.token : null; - let mode = context?.mode ? String(context.mode) : "sponsor"; - let chainId = query['chainId'] ?? body.params[3]; - const api_key = query['apiKey'] ?? body.params[4]; - let sponsorDetails = false, estimate = true; - if (body.method) { - switch(body.method) { - case 'pm_getPaymasterData': { - estimate = false; - sponsorDetails = true; - } - case 'pm_getPaymasterStubData': { - chainId = BigNumber.from(body.params[2]).toNumber(); - context = body.params[3]; - gasToken = context?.token ? context.token : null; - mode = context?.mode ? String(context.mode) : "sponsor"; - break; - }; - case 'pm_sponsorUserOperation': { - break; - }; - default: { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_METHOD }); - break; - } - } - } - if (!api_key) - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - console.log('entryPoint: ', entryPoint); - if ((entryPoint != SUPPORTED_ENTRYPOINTS.EPV_06) && (entryPoint != SUPPORTED_ENTRYPOINTS.EPV_07)) - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_ENTRYPOINT }) - let customPaymasters = []; - let multiTokenPaymasters = []; - let multiTokenOracles = []; - let privateKey = ''; - let supportedNetworks; - let noOfTxns; - let txnMode; - let indexerEndpoint; - let sponsorName = '', sponsorImage = ''; - 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()); - } - if (secrets['MULTI_TOKEN_PAYMASTERS']) { - const buffer = Buffer.from(secrets['MULTI_TOKEN_PAYMASTERS'], 'base64'); - multiTokenPaymasters = JSON.parse(buffer.toString()); - } - if (secrets['MULTI_TOKEN_ORACLES']) { - const buffer = Buffer.from(secrets['MULTI_TOKEN_ORACLES'], 'base64'); - multiTokenOracles = JSON.parse(buffer.toString()); - } - sponsorName = secrets['SPONSOR_NAME']; - sponsorImage = secrets['LOGO_URL']; - privateKey = secrets['PRIVATE_KEY']; - supportedNetworks = secrets['SUPPORTED_NETWORKS']; - noOfTxns = secrets['NO_OF_TRANSACTIONS_IN_A_MONTH'] ?? 10; - txnMode = secrets['TRANSACTION_LIMIT'] ?? 0; - indexerEndpoint = secrets['INDEXER_ENDPOINT'] ?? process.env.DEFAULT_INDEXER_ENDPOINT; - } 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 }) + server.post("/", async function (request, reply) { + try { + printRequest("/", request, server.log); + const query: any = request.query; + const body: any = request.body; + if (!body) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.EMPTY_BODY }); + const userOp = body.params[0]; + const entryPoint = body.params[1]; + let context = body.params[2]; + let gasToken = context?.token ? context.token : null; + let mode = context?.mode ? String(context.mode) : "sponsor"; + let chainId = query["chainId"] ?? body.params[3]; + const api_key = query["apiKey"] ?? body.params[4]; + let sponsorDetails = false, + estimate = true; + if (body.method) { + switch (body.method) { + case "pm_getPaymasterData": { + estimate = false; + sponsorDetails = true; } - if (record['ERC20_PAYMASTERS']) { - const buffer = Buffer.from(record['ERC20_PAYMASTERS'], 'base64'); - customPaymasters = JSON.parse(buffer.toString()); + case "pm_getPaymasterStubData": { + chainId = BigNumber.from(body.params[2]).toNumber(); + context = body.params[3]; + gasToken = context?.token ? context.token : null; + mode = context?.mode ? String(context.mode) : "sponsor"; + break; } - if (record['MULTI_TOKEN_PAYMASTERS']) { - const buffer = Buffer.from(record['MULTI_TOKEN_PAYMASTERS'], 'base64'); - multiTokenPaymasters = JSON.parse(buffer.toString()); + case "pm_sponsorUserOperation": { + break; } - if (record['MULTI_TOKEN_ORACLES']) { - const buffer = Buffer.from(record['MULTI_TOKEN_ORACLES'], 'base64'); - multiTokenOracles = JSON.parse(buffer.toString()); + default: { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_METHOD }); + break; } - sponsorName = record['SPONSOR_NAME']; - sponsorImage = record['LOGO_URL']; - privateKey = decode(record['PRIVATE_KEY']); - supportedNetworks = record['SUPPORTED_NETWORKS']; - noOfTxns = record['NO_OF_TRANSACTIONS_IN_A_MONTH']; - txnMode = record['TRANSACTION_LIMIT']; - indexerEndpoint = record['INDEXER_ENDPOINT'] ?? process.env.DEFAULT_INDEXER_ENDPOINT; } - - if ( - !userOp || - !entryPoint || - !chainId || - !mode || - isNaN(chainId) - ) { - server.log.info("Incomplete body data provided") - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_DATA }); + } + if (!api_key) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + console.log("entryPoint: ", entryPoint); + if ( + entryPoint != SUPPORTED_ENTRYPOINTS.EPV_06 && + entryPoint != SUPPORTED_ENTRYPOINTS.EPV_07 + ) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_ENTRYPOINT }); + let customPaymasters = []; + let multiTokenPaymasters = []; + let multiTokenOracles = []; + let privateKey = ""; + let supportedNetworks; + let noOfTxns; + let txnMode; + let indexerEndpoint; + let sponsorName = "", + sponsorImage = ""; + 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 (server.config.SUPPORTED_NETWORKS == '' && !SupportedNetworks) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + if (secrets["ERC20_PAYMASTERS"]) { + const buffer = Buffer.from(secrets["ERC20_PAYMASTERS"], "base64"); + customPaymasters = JSON.parse(buffer.toString()); + } + if (secrets["MULTI_TOKEN_PAYMASTERS"]) { + const buffer = Buffer.from( + secrets["MULTI_TOKEN_PAYMASTERS"], + "base64" + ); + multiTokenPaymasters = JSON.parse(buffer.toString()); + } + if (secrets["MULTI_TOKEN_ORACLES"]) { + const buffer = Buffer.from(secrets["MULTI_TOKEN_ORACLES"], "base64"); + multiTokenOracles = JSON.parse(buffer.toString()); + } + sponsorName = secrets["SPONSOR_NAME"]; + sponsorImage = secrets["LOGO_URL"]; + privateKey = secrets["PRIVATE_KEY"]; + supportedNetworks = secrets["SUPPORTED_NETWORKS"]; + noOfTxns = secrets["NO_OF_TRANSACTIONS_IN_A_MONTH"] ?? 10; + txnMode = secrets["TRANSACTION_LIMIT"] ?? 0; + indexerEndpoint = + secrets["INDEXER_ENDPOINT"] ?? process.env.DEFAULT_INDEXER_ENDPOINT; + } 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()); + } + if (record["MULTI_TOKEN_PAYMASTERS"]) { + const buffer = Buffer.from( + record["MULTI_TOKEN_PAYMASTERS"], + "base64" + ); + multiTokenPaymasters = JSON.parse(buffer.toString()); + } + if (record["MULTI_TOKEN_ORACLES"]) { + const buffer = Buffer.from(record["MULTI_TOKEN_ORACLES"], "base64"); + multiTokenOracles = JSON.parse(buffer.toString()); } + sponsorName = record["SPONSOR_NAME"]; + sponsorImage = record["LOGO_URL"]; + privateKey = decode(record["PRIVATE_KEY"]); + supportedNetworks = record["SUPPORTED_NETWORKS"]; + noOfTxns = record["NO_OF_TRANSACTIONS_IN_A_MONTH"]; + txnMode = record["TRANSACTION_LIMIT"]; + indexerEndpoint = + record["INDEXER_ENDPOINT"] ?? process.env.DEFAULT_INDEXER_ENDPOINT; + } + + if (!userOp || !entryPoint || !chainId || !mode || isNaN(chainId)) { + server.log.info("Incomplete body data provided"); + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_DATA }); + } - if ( - mode.toLowerCase() == 'erc20' && - !(PAYMASTER_ADDRESS[chainId] && PAYMASTER_ADDRESS[chainId][gasToken]) && - !(customPaymasters[chainId] && customPaymasters[chainId][gasToken]) - ) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK_TOKEN }) + if (server.config.SUPPORTED_NETWORKS == "" && !SupportedNetworks) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + } - if (gasToken && ethers.utils.isAddress(gasToken)) gasToken = ethers.utils.getAddress(gasToken) + if ( + mode.toLowerCase() == "erc20" && + !(PAYMASTER_ADDRESS[chainId] && PAYMASTER_ADDRESS[chainId][gasToken]) && + !(customPaymasters[chainId] && customPaymasters[chainId][gasToken]) + ) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK_TOKEN }); - if (mode.toLowerCase() == 'multitoken' && - !(multiTokenPaymasters[chainId] && multiTokenPaymasters[chainId][gasToken]) && - !(multiTokenOracles[chainId] && multiTokenOracles[chainId][gasToken]) - ) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK_TOKEN }) + if (gasToken && ethers.utils.isAddress(gasToken)) + gasToken = ethers.utils.getAddress(gasToken); - const networkConfig = getNetworkConfig(chainId, supportedNetworks ?? '', entryPoint); - if (!networkConfig) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + if ( + mode.toLowerCase() == "multitoken" && + !( + multiTokenPaymasters[chainId] && + multiTokenPaymasters[chainId][gasToken] + ) && + !(multiTokenOracles[chainId] && multiTokenOracles[chainId][gasToken]) + ) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK_TOKEN }); - let result: any; - switch (mode.toLowerCase()) { - case 'sponsor': { - const date = new Date(); - const provider = new providers.JsonRpcProvider(networkConfig.bundler); - const signer = new Wallet(privateKey, provider) - if (txnMode) { - const signerAddress = await signer.getAddress(); - const IndexerData = await getIndexerData(signerAddress, userOp.sender, date.getMonth(), date.getFullYear(), noOfTxns, indexerEndpoint); - if (IndexerData.length >= noOfTxns) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.QUOTA_EXCEEDED }) - } - const validUntil = context?.validUntil ? new Date(context.validUntil) : date; - const validAfter = context?.validAfter ? new Date(context.validAfter) : date; - const hex = (Number((validUntil.valueOf() / 1000).toFixed(0)) + 600).toString(16); - const hex1 = (Number((validAfter.valueOf() / 1000).toFixed(0)) - 60).toString(16); - let str = '0x' - let str1 = '0x' - for (let i = 0; i < 14 - hex.length; i++) { - str += '0'; - } - for (let i = 0; i < 14 - hex1.length; i++) { - str1 += '0'; - } - str += hex; - str1 += hex1; - if (entryPoint == SUPPORTED_ENTRYPOINTS.EPV_06) - result = await paymaster.signV06(userOp, str, str1, entryPoint, networkConfig.contracts.etherspotPaymasterAddress, networkConfig.bundler, signer, estimate, server.log); - else result = await paymaster.signV07(userOp, str, str1, entryPoint, networkConfig.contracts.etherspotPaymasterAddress, networkConfig.bundler, signer, estimate, server.log); - break; + const networkConfig = getNetworkConfig( + chainId, + supportedNetworks ?? "", + entryPoint + ); + if (!networkConfig) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + + let result: any; + switch (mode.toLowerCase()) { + case "sponsor": { + const date = new Date(); + const provider = new providers.JsonRpcProvider(networkConfig.bundler); + const signer = new Wallet(privateKey, provider); + if (txnMode) { + const signerAddress = await signer.getAddress(); + const IndexerData = await getIndexerData( + signerAddress, + userOp.sender, + date.getMonth(), + date.getFullYear(), + noOfTxns, + indexerEndpoint + ); + if (IndexerData.length >= noOfTxns) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.QUOTA_EXCEEDED }); } - case 'erc20': { - if (entryPoint !== SUPPORTED_ENTRYPOINTS.EPV_06) - throw new Error('Currently only 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 entryPoint address is supported') - 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, server.log); - break; + const validUntil = context?.validUntil + ? new Date(context.validUntil) + : date; + const validAfter = context?.validAfter + ? new Date(context.validAfter) + : date; + const hex = ( + Number((validUntil.valueOf() / 1000).toFixed(0)) + 600 + ).toString(16); + const hex1 = ( + Number((validAfter.valueOf() / 1000).toFixed(0)) - 60 + ).toString(16); + let str = "0x"; + let str1 = "0x"; + for (let i = 0; i < 14 - hex.length; i++) { + str += "0"; } - case 'multitoken': { - if (entryPoint !== SUPPORTED_ENTRYPOINTS.EPV_06) - throw new Error('Currently only 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 entryPoint address is supported') - const date = new Date(); - const provider = new providers.JsonRpcProvider(networkConfig.bundler); - const signer = new Wallet(privateKey, provider) - const validUntil = context.validUntil ? new Date(context.validUntil) : date; - const validAfter = context.validAfter ? new Date(context.validAfter) : date; - const hex = (Number((validUntil.valueOf() / 1000).toFixed(0)) + 600).toString(16); - const hex1 = (Number((validAfter.valueOf() / 1000).toFixed(0)) - 60).toString(16); - let str = '0x' - let str1 = '0x' - for (let i = 0; i < 14 - hex.length; i++) { - str += '0'; - } - for (let i = 0; i < 14 - hex1.length; i++) { - str1 += '0'; - } - str += hex; - str1 += hex1; - if (!networkConfig.MultiTokenPaymasterOracleUsed || - !(networkConfig.MultiTokenPaymasterOracleUsed == "orochi" || networkConfig.MultiTokenPaymasterOracleUsed == "chainlink")) - throw new Error("Oracle is not Defined/Invalid"); - result = await paymaster.signMultiTokenPaymaster(userOp, str, str1, entryPoint, multiTokenPaymasters[chainId][gasToken], gasToken, multiTokenOracles[chainId][gasToken], networkConfig.bundler, signer, networkConfig.MultiTokenPaymasterOracleUsed, server.log); - break; + for (let i = 0; i < 14 - hex1.length; i++) { + str1 += "0"; } - default : { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_MODE }); + str += hex; + str1 += hex1; + if (entryPoint == SUPPORTED_ENTRYPOINTS.EPV_06) + result = await paymaster.signV06( + userOp, + str, + str1, + entryPoint, + networkConfig.contracts.etherspotPaymasterAddress, + networkConfig.bundler, + signer, + estimate, + server.log + ); + else + result = await paymaster.signV07( + userOp, + str, + str1, + entryPoint, + networkConfig.contracts.etherspotPaymasterAddress, + networkConfig.bundler, + signer, + estimate, + server.log + ); + break; + } + case "erc20": { + if (entryPoint !== SUPPORTED_ENTRYPOINTS.EPV_06) + throw new Error( + "Currently only 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 entryPoint address is supported" + ); + 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, + server.log + ); + break; + } + case "multitoken": { + if (entryPoint !== SUPPORTED_ENTRYPOINTS.EPV_06) + throw new Error( + "Currently only 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 entryPoint address is supported" + ); + const date = new Date(); + const provider = new providers.JsonRpcProvider(networkConfig.bundler); + const signer = new Wallet(privateKey, provider); + const validUntil = context.validUntil + ? new Date(context.validUntil) + : date; + const validAfter = context.validAfter + ? new Date(context.validAfter) + : date; + const hex = ( + Number((validUntil.valueOf() / 1000).toFixed(0)) + 600 + ).toString(16); + const hex1 = ( + Number((validAfter.valueOf() / 1000).toFixed(0)) - 60 + ).toString(16); + let str = "0x"; + let str1 = "0x"; + for (let i = 0; i < 14 - hex.length; i++) { + str += "0"; } + for (let i = 0; i < 14 - hex1.length; i++) { + str1 += "0"; + } + str += hex; + str1 += hex1; + if ( + !networkConfig.MultiTokenPaymasterOracleUsed || + !( + networkConfig.MultiTokenPaymasterOracleUsed == "orochi" || + networkConfig.MultiTokenPaymasterOracleUsed == "chainlink" + ) + ) + throw new Error("Oracle is not Defined/Invalid"); + result = await paymaster.signMultiTokenPaymaster( + userOp, + str, + str1, + entryPoint, + multiTokenPaymasters[chainId][gasToken], + gasToken, + multiTokenOracles[chainId][gasToken], + networkConfig.bundler, + signer, + networkConfig.MultiTokenPaymasterOracleUsed, + server.log + ); + break; + } + default: { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_MODE }); } - server.log.info(result, 'Response sent: '); - if (sponsorDetails) result.sponsor = { name: sponsorName, icon: sponsorImage }; - if (body.jsonrpc) - return reply.code(ReturnCode.SUCCESS).send({ jsonrpc: body.jsonrpc, id: body.id, result, error: null }) - return reply.code(ReturnCode.SUCCESS).send(result); - } 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 }); } + server.log.info(result, "Response sent: "); + if (sponsorDetails) + result.sponsor = { name: sponsorName, icon: sponsorImage }; + if (body.jsonrpc) + return reply + .code(ReturnCode.SUCCESS) + .send({ jsonrpc: body.jsonrpc, id: body.id, result, error: null }); + return reply.code(ReturnCode.SUCCESS).send(result); + } 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 }); } - ); + }); server.post( "/pimlicoAddress", @@ -277,12 +410,14 @@ const routes: FastifyPluginAsync = async (server) => { const entryPoint = body.params[0]; const context = body.params[1]; const gasToken = context ? context.token : null; - const chainId = query['chainId'] ?? body.params[2]; - const api_key = query['apiKey'] ?? body.params[3]; + const chainId = query["chainId"] ?? body.params[2]; + const api_key = query["apiKey"] ?? body.params[3]; if (!api_key) - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); let customPaymasters = []; - let privateKey = ''; + let privateKey = ""; let supportedNetworks; if (!unsafeMode) { const AWSresponse = await client.send( @@ -290,230 +425,395 @@ const routes: FastifyPluginAsync = async (server) => { SecretId: prefixSecretId + api_key, }) ); - const secrets = JSON.parse(AWSresponse.SecretString ?? '{}'); - if (!secrets['PRIVATE_KEY']) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - if (secrets['ERC20_PAYMASTERS']) { - const buffer = Buffer.from(secrets['ERC20_PAYMASTERS'], 'base64'); + const secrets = JSON.parse(AWSresponse.SecretString ?? "{}"); + if (!secrets["PRIVATE_KEY"]) + 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']; + privateKey = secrets["PRIVATE_KEY"]; + supportedNetworks = secrets["SUPPORTED_NETWORKS"]; } else { - 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'); + 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"); customPaymasters = JSON.parse(buffer.toString()); } - privateKey = decode(record['PRIVATE_KEY']); - supportedNetworks = record['SUPPORTED_NETWORKS']; + privateKey = decode(record["PRIVATE_KEY"]); + supportedNetworks = record["SUPPORTED_NETWORKS"]; } - if (!privateKey) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - if ( - !entryPoint || - !gasToken || - !chainId || - isNaN(chainId) - ) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_DATA }); + if (!privateKey) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + if (!entryPoint || !gasToken || !chainId || isNaN(chainId)) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_DATA }); } - if (server.config.SUPPORTED_NETWORKS == '' && !SupportedNetworks) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + if (server.config.SUPPORTED_NETWORKS == "" && !SupportedNetworks) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); } - const networkConfig = getNetworkConfig(chainId, supportedNetworks ?? '', entryPoint); - if (!networkConfig) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + const networkConfig = getNetworkConfig( + chainId, + supportedNetworks ?? "", + entryPoint + ); + if (!networkConfig) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); let result; - if (customPaymasters[chainId] && customPaymasters[chainId][gasToken]) result = { message: customPaymasters[chainId][gasToken] } + if (customPaymasters[chainId] && customPaymasters[chainId][gasToken]) + result = { message: customPaymasters[chainId][gasToken] }; else { - if (!(PAYMASTER_ADDRESS[chainId] && PAYMASTER_ADDRESS[chainId][gasToken])) return reply.code(ReturnCode.FAILURE).send({ error: "Invalid network/token" }) - result = { message: PAYMASTER_ADDRESS[chainId][gasToken] } + 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: '); + server.log.info(result, "Response sent: "); if (body.jsonrpc) - return reply.code(ReturnCode.SUCCESS).send({ jsonrpc: body.jsonrpc, id: body.id, message: result.message, error: null }) + return reply + .code(ReturnCode.SUCCESS) + .send({ + jsonrpc: body.jsonrpc, + id: body.id, + message: result.message, + error: null, + }); return reply.code(ReturnCode.SUCCESS).send(result); } 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 }); + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + return reply + .code(ReturnCode.FAILURE) + .send({ error: err.message ?? ErrorMessage.FAILED_TO_PROCESS }); } } - ) + ); - server.post( - "/whitelist", - async function (request, reply) { - try { - printRequest("/whitelist", request, server.log); - const body: any = request.body; - const query: any = request.query; - const address = body.params[0]; - 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 = ''; - 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']) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - privateKey = secrets['PRIVATE_KEY']; - supportedNetworks = secrets['SUPPORTED_NETWORKS']; - } else { - 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']; - } - if (!privateKey) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - if ( - !Array.isArray(address) || - address.length > 10 || - !chainId || - isNaN(chainId) - ) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_DATA }); - } - if (server.config.SUPPORTED_NETWORKS == '' && !SupportedNetworks) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); - } - const networkConfig = getNetworkConfig(chainId, supportedNetworks ?? '', SUPPORTED_ENTRYPOINTS.EPV_06); - if (!networkConfig) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); - const validAddresses = address.every(ethers.utils.isAddress); - if (!validAddresses) return reply.code(ReturnCode.FAILURE).send({ error: "Invalid Address passed" }); - const result = await paymaster.whitelistAddresses(address, networkConfig.contracts.etherspotPaymasterAddress, networkConfig.bundler, privateKey, chainId, server.log); - server.log.info(result, 'Response sent: '); - if (body.jsonrpc) - return reply.code(ReturnCode.SUCCESS).send({ jsonrpc: body.jsonrpc, id: body.id, result, error: null }) - return reply.code(ReturnCode.SUCCESS).send(result); - } 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 }) + server.post("/whitelist", async function (request, reply) { + try { + printRequest("/whitelist", request, server.log); + const body: any = request.body; + const query: any = request.query; + const address = body.params[0]; + 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 = ""; + 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"]) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + privateKey = secrets["PRIVATE_KEY"]; + supportedNetworks = secrets["SUPPORTED_NETWORKS"]; + } else { + 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"]; + } + if (!privateKey) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + if ( + !Array.isArray(address) || + address.length > 10 || + !chainId || + isNaN(chainId) + ) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_DATA }); } + if (server.config.SUPPORTED_NETWORKS == "" && !SupportedNetworks) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + } + const networkConfig = getNetworkConfig( + chainId, + supportedNetworks ?? "", + SUPPORTED_ENTRYPOINTS.EPV_06 + ); + if (!networkConfig) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + const validAddresses = address.every(ethers.utils.isAddress); + if (!validAddresses) + return reply + .code(ReturnCode.FAILURE) + .send({ error: "Invalid Address passed" }); + const result = await paymaster.whitelistAddresses( + address, + networkConfig.contracts.etherspotPaymasterAddress, + networkConfig.bundler, + privateKey, + chainId, + server.log + ); + server.log.info(result, "Response sent: "); + if (body.jsonrpc) + return reply + .code(ReturnCode.SUCCESS) + .send({ jsonrpc: body.jsonrpc, id: body.id, result, error: null }); + return reply.code(ReturnCode.SUCCESS).send(result); + } 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 }); } - ) + }); 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]; - 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 = ''; - 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']) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - privateKey = secrets['PRIVATE_KEY']; - supportedNetworks = secrets['SUPPORTED_NETWORKS']; - } else { - 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']; - } - if (!privateKey) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - if ( - !Array.isArray(address) || - address.length > 10 || - !chainId || - isNaN(chainId) - ) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_DATA }); - } - if (server.config.SUPPORTED_NETWORKS == '' && !SupportedNetworks) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); - } - const networkConfig = getNetworkConfig(chainId, supportedNetworks ?? '', SUPPORTED_ENTRYPOINTS.EPV_06); - if (!networkConfig) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); - const validAddresses = address.every(ethers.utils.isAddress); - if (!validAddresses) return reply.code(ReturnCode.FAILURE).send({ error: "Invalid Address passed" }); - const result = await paymaster.removeWhitelistAddress(address, networkConfig.contracts.etherspotPaymasterAddress, networkConfig.bundler, privateKey, chainId, server.log); - if (body.jsonrpc) - return reply.code(ReturnCode.SUCCESS).send({ jsonrpc: body.jsonrpc, id: body.id, result, error: null }) - return reply.code(ReturnCode.SUCCESS).send(result); + const query: any = request.query; + const address = body.params[0]; + 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 = ""; + 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"]) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + privateKey = secrets["PRIVATE_KEY"]; + supportedNetworks = secrets["SUPPORTED_NETWORKS"]; + } else { + 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"]; + } + if (!privateKey) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + if ( + !Array.isArray(address) || + address.length > 10 || + !chainId || + isNaN(chainId) + ) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_DATA }); + } + if (server.config.SUPPORTED_NETWORKS == "" && !SupportedNetworks) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + } + const networkConfig = getNetworkConfig( + chainId, + supportedNetworks ?? "", + SUPPORTED_ENTRYPOINTS.EPV_06 + ); + if (!networkConfig) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + const validAddresses = address.every(ethers.utils.isAddress); + if (!validAddresses) + return reply + .code(ReturnCode.FAILURE) + .send({ error: "Invalid Address passed" }); + const result = await paymaster.removeWhitelistAddress( + address, + networkConfig.contracts.etherspotPaymasterAddress, + networkConfig.bundler, + privateKey, + chainId, + server.log + ); + if (body.jsonrpc) + return reply + .code(ReturnCode.SUCCESS) + .send({ jsonrpc: body.jsonrpc, id: body.id, result, error: null }); + return reply.code(ReturnCode.SUCCESS).send(result); } 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 }) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + return reply + .code(ReturnCode.FAILURE) + .send({ error: err.message ?? ErrorMessage.FAILED_TO_PROCESS }); } - }) + }); - server.post( - "/checkWhitelist", - async function (request, reply) { - try { - 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[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 = ''; - 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']) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - privateKey = secrets['PRIVATE_KEY']; - supportedNetworks = secrets['SUPPORTED_NETWORKS']; - } else { - 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']; - } - if (!privateKey) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - if ( - !accountAddress || - !ethers.utils.isAddress(accountAddress) || - !chainId || - isNaN(chainId) - ) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_DATA }); - } - if (server.config.SUPPORTED_NETWORKS == '' && !SupportedNetworks) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); - } - const networkConfig = getNetworkConfig(chainId, supportedNetworks ?? '', SUPPORTED_ENTRYPOINTS.EPV_06); - if (!networkConfig) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); - const response = await paymaster.checkWhitelistAddress(accountAddress, networkConfig.contracts.etherspotPaymasterAddress, networkConfig.bundler, privateKey, server.log); - server.log.info(response, 'Response sent: '); - if (body.jsonrpc) - return reply.code(ReturnCode.SUCCESS).send({ jsonrpc: body.jsonrpc, id: body.id, result: { message: response === true ? 'Already added' : 'Not added yet' }, error: null }) - return reply.code(ReturnCode.SUCCESS).send({ message: response === true ? 'Already added' : 'Not added yet' }); - } 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 }) + server.post("/checkWhitelist", async function (request, reply) { + try { + 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[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 = ""; + 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"]) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + privateKey = secrets["PRIVATE_KEY"]; + supportedNetworks = secrets["SUPPORTED_NETWORKS"]; + } else { + 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"]; } + if (!privateKey) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + if ( + !accountAddress || + !ethers.utils.isAddress(accountAddress) || + !chainId || + isNaN(chainId) + ) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_DATA }); + } + if (server.config.SUPPORTED_NETWORKS == "" && !SupportedNetworks) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + } + const networkConfig = getNetworkConfig( + chainId, + supportedNetworks ?? "", + SUPPORTED_ENTRYPOINTS.EPV_06 + ); + if (!networkConfig) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + const response = await paymaster.checkWhitelistAddress( + accountAddress, + networkConfig.contracts.etherspotPaymasterAddress, + networkConfig.bundler, + privateKey, + server.log + ); + server.log.info(response, "Response sent: "); + if (body.jsonrpc) + return reply + .code(ReturnCode.SUCCESS) + .send({ + jsonrpc: body.jsonrpc, + id: body.id, + result: { + message: response === true ? "Already added" : "Not added yet", + }, + error: null, + }); + return reply + .code(ReturnCode.SUCCESS) + .send({ + message: response === true ? "Already added" : "Not added yet", + }); + } 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 }); } - ) + }); server.post( "/deposit", @@ -524,11 +824,13 @@ const routes: FastifyPluginAsync = async (server) => { const body: any = request.body; const query: any = request.query; const amount = body.params[0]; - const chainId = query['chainId'] ?? body.params[1]; - const api_key = query['apiKey'] ?? body.params[2]; + 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 = ''; + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + let privateKey = ""; let supportedNetworks; if (!unsafeMode) { const AWSresponse = await client.send( @@ -536,37 +838,66 @@ const routes: FastifyPluginAsync = async (server) => { SecretId: prefixSecretId + api_key, }) ); - const secrets = JSON.parse(AWSresponse.SecretString ?? '{}'); - if (!secrets['PRIVATE_KEY']) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - privateKey = secrets['PRIVATE_KEY']; - supportedNetworks = secrets['SUPPORTED_NETWORKS']; + const secrets = JSON.parse(AWSresponse.SecretString ?? "{}"); + if (!secrets["PRIVATE_KEY"]) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + privateKey = secrets["PRIVATE_KEY"]; + supportedNetworks = secrets["SUPPORTED_NETWORKS"]; } else { - 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']; + 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"]; } - if ( - isNaN(amount) || - !chainId || - isNaN(chainId) - ) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_DATA }); + if (isNaN(amount) || !chainId || isNaN(chainId)) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_DATA }); } - if (server.config.SUPPORTED_NETWORKS == '' && !SupportedNetworks) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + if (server.config.SUPPORTED_NETWORKS == "" && !SupportedNetworks) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); } - const networkConfig = getNetworkConfig(chainId, supportedNetworks ?? '', SUPPORTED_ENTRYPOINTS.EPV_06); - if (!networkConfig) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); - return await paymaster.deposit(amount, networkConfig.contracts.etherspotPaymasterAddress, networkConfig.bundler, privateKey, chainId, server.log); + const networkConfig = getNetworkConfig( + chainId, + supportedNetworks ?? "", + SUPPORTED_ENTRYPOINTS.EPV_06 + ); + if (!networkConfig) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + return await paymaster.deposit( + amount, + networkConfig.contracts.etherspotPaymasterAddress, + networkConfig.bundler, + privateKey, + chainId, + true, + server.log + ); } 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 }) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + return reply + .code(ReturnCode.FAILURE) + .send({ error: err.message ?? ErrorMessage.FAILED_TO_PROCESS }); } } - ) + ); server.post( "/deposit/v2", @@ -577,11 +908,13 @@ const routes: FastifyPluginAsync = async (server) => { const body: any = request.body; const query: any = request.query; const amount = body.params[0]; - const chainId = query['chainId'] ?? body.params[1]; - const api_key = query['apiKey'] ?? body.params[2]; + 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 = ''; + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + let privateKey = ""; let supportedNetworks; if (!unsafeMode) { const AWSresponse = await client.send( @@ -589,39 +922,75 @@ const routes: FastifyPluginAsync = async (server) => { SecretId: prefixSecretId + api_key, }) ); - const secrets = JSON.parse(AWSresponse.SecretString ?? '{}'); - if (!secrets['PRIVATE_KEY']) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - privateKey = secrets['PRIVATE_KEY']; - supportedNetworks = secrets['SUPPORTED_NETWORKS']; + const secrets = JSON.parse(AWSresponse.SecretString ?? "{}"); + if (!secrets["PRIVATE_KEY"]) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + privateKey = secrets["PRIVATE_KEY"]; + supportedNetworks = secrets["SUPPORTED_NETWORKS"]; } else { - 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']; + 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"]; } - if ( - isNaN(amount) || - !chainId || - isNaN(chainId) - ) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_DATA }); + if (isNaN(amount) || !chainId || isNaN(chainId)) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_DATA }); } - if (server.config.SUPPORTED_NETWORKS == '' && !SupportedNetworks) { - return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + if (server.config.SUPPORTED_NETWORKS == "" && !SupportedNetworks) { + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); } - const networkConfig = getNetworkConfig(chainId, supportedNetworks ?? '', SUPPORTED_ENTRYPOINTS.EPV_07); - if (!networkConfig) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); - return await paymaster.deposit(amount, networkConfig.contracts.etherspotPaymasterAddress, networkConfig.bundler, privateKey, chainId, server.log); + const networkConfig = getNetworkConfig( + chainId, + supportedNetworks ?? "", + SUPPORTED_ENTRYPOINTS.EPV_07 + ); + if (!networkConfig) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + return await paymaster.deposit( + amount, + networkConfig.contracts.etherspotPaymasterAddress, + networkConfig.bundler, + privateKey, + chainId, + false, + server.log + ); } 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 }) + return reply + .code(ReturnCode.FAILURE) + .send({ error: ErrorMessage.INVALID_API_KEY }); + return reply + .code(ReturnCode.FAILURE) + .send({ error: err.message ?? ErrorMessage.FAILED_TO_PROCESS }); } } - ) + ); - async function getIndexerData(sponsor: string, sender: string, month: number, year: number, noOfTxns: number, endpoint: string): Promise { + async function getIndexerData( + sponsor: string, + sender: string, + month: number, + year: number, + noOfTxns: number, + endpoint: string + ): Promise { try { const query = gql` query { From ecdf90c1fc543355cabf81f7dcc785a24a3678c9 Mon Sep 17 00:00:00 2001 From: Jineshdarjee Date: Tue, 18 Jun 2024 15:43:59 +0530 Subject: [PATCH 4/4] Reverted file --- backend/src/utils/common.ts | 98 ++++++++++++------------------------- 1 file changed, 30 insertions(+), 68 deletions(-) diff --git a/backend/src/utils/common.ts b/backend/src/utils/common.ts index 89dd146..bfc2624 100644 --- a/backend/src/utils/common.ts +++ b/backend/src/utils/common.ts @@ -1,52 +1,32 @@ import { FastifyBaseLogger, FastifyRequest } from "fastify"; import { BigNumber, ethers } from "ethers"; import { Database } from "sqlite3"; -import SupportedNetworks from "../../config.json"; +import SupportedNetworks from "../../config.json" assert { type: "json" }; import { EtherscanResponse, getEtherscanFeeResponse } from "./interface.js"; -export function printRequest( - methodName: string, - request: FastifyRequest, - log: FastifyBaseLogger -) { +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, - entryPoint: string -) { - 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 && chain["entryPoint"] == entryPoint; - }); +export function getNetworkConfig(key: any, supportedNetworks: any, entryPoint: string) { + 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 && chain["entryPoint"] == entryPoint }); } else - return SupportedNetworks.find( - (chain) => chain.chainId == key && chain.entryPoint == entryPoint - ); + return SupportedNetworks.find((chain) => chain.chainId == key && chain.entryPoint == entryPoint); } -export async function getSQLdata( - apiKey: string, - db: Database, - log: FastifyBaseLogger -) { +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); - } - ); - }); + 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); @@ -54,55 +34,36 @@ export async function getSQLdata( } } -export async function getEtherscanFee( - chainId: number, - log?: FastifyBaseLogger -): Promise { +export async function getEtherscanFee(chainId: number, log?: FastifyBaseLogger): Promise { try { const etherscanUrlsBase64 = process.env.ETHERSCAN_GAS_ORACLES; if (etherscanUrlsBase64) { - const buffer = Buffer.from(etherscanUrlsBase64, "base64"); + const buffer = Buffer.from(etherscanUrlsBase64, 'base64'); const etherscanUrls = JSON.parse(buffer.toString()); - console.log("etherscanUrl: ", etherscanUrls[chainId]); + console.log('etherscanUrl: ', etherscanUrls[chainId]); if (etherscanUrls[chainId]) { const data = await fetch(etherscanUrls[chainId]); const response: EtherscanResponse = await data.json(); - console.log("Etherscan Response: ", response); - if ( - response.result && - typeof response.result === "object" && - response.status === "1" - ) { - console.log( - "setting maxFeePerGas and maxPriorityFeePerGas as received" - ); - const maxFeePerGas = ethers.utils.parseUnits( - response.result.suggestBaseFee, - "gwei" - ); - const fastGasPrice = ethers.utils.parseUnits( - response.result.FastGasPrice, - "gwei" - ); + console.log('Etherscan Response: ', response); + if (response.result && typeof response.result === "object" && response.status === "1") { + console.log('setting maxFeePerGas and maxPriorityFeePerGas as received') + const maxFeePerGas = ethers.utils.parseUnits(response.result.suggestBaseFee, 'gwei') + const fastGasPrice = ethers.utils.parseUnits(response.result.FastGasPrice, 'gwei') return { maxPriorityFeePerGas: fastGasPrice.sub(maxFeePerGas), maxFeePerGas, gasPrice: maxFeePerGas, - }; + } } - if ( - response.result && - typeof response.result === "string" && - response.jsonrpc - ) { - const gasPrice = BigNumber.from(response.result); - console.log("setting gas price as received"); + if (response.result && typeof response.result === "string" && response.jsonrpc) { + const gasPrice = BigNumber.from(response.result) + console.log('setting gas price as received') return { maxFeePerGas: gasPrice, maxPriorityFeePerGas: gasPrice, - gasPrice: gasPrice, - }; + gasPrice: gasPrice + } } return null; } @@ -112,8 +73,9 @@ export async function getEtherscanFee( } catch (err) { if (log) { log.error(err); - log.info("fetching from provider"); + log.info('fetching from provider'); } return null; } } +