From 58a37f8e6861e8418b758540d30b2540520523c6 Mon Sep 17 00:00:00 2001 From: Jineshdarjee <118883810+Jineshdarjee@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:49:44 +0530 Subject: [PATCH] Unit test (#110) * Added unit test case for epv07 * Reverted files * Reverted file * Reverted file --- backend/jest.config.js | 48 +- backend/src/paymaster/index.test.ts | 1163 ++++++++++++++++++---- backend/src/paymaster/pimlico.test.ts | 409 +++++--- backend/src/routes/index.ts | 1289 ++++++++++++++++--------- 4 files changed, 2121 insertions(+), 788 deletions(-) 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/src/paymaster/index.test.ts b/backend/src/paymaster/index.test.ts index 5b26a9a..e77770e 100644 --- a/backend/src/paymaster/index.test.ts +++ b/backend/src/paymaster/index.test.ts @@ -2,320 +2,1151 @@ import { ethers, providers, Wallet } from "ethers"; import { Paymaster } from "./index.js"; import { PAYMASTER_ADDRESS } from "../constants/Pimlico.js"; +import MultiTokenPaymasterAbi from "../abi/MultiTokenPaymasterAbi.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 delay = (ms: any) => new Promise((resolve) => setTimeout(resolve, ms)); + const paymaster = new Paymaster("0", "1150000"); + const relayerKey = + "0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb2"; // Testing wallet private key only has Mumbai funds in it + const chainId = 80002; + const Mock_Valid_Until = "0x000000ffffffff"; // max value + const Mock_Valid_After = "0x0000000000001234"; // min value + const feeTokenMultiToken = "0x453478e2e0c846c069e544405d5877086960bef2"; + const oracleAggregatorMultiToken = + "0xbf3ff099fb6c23296fd192df643ad49fced658d0"; + const ethPriceMultiToken = "3099"; + const oracleNameMultiToken = "orochi"; + + const paymasterAddressV06 = "0xe893a26dd53b325bffaacdfa224692eff4c448c4"; + const paymasterAddressV07 = "0x810FA4C915015b703db0878CF2B9344bEB254a40"; + const paymasterAddressMultiToken = + "0xe85649152d15825f2226b2d9c49c07b1cd2b36c7"; + const entryPointAddressV06 = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; + const entryPointAddressV07 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032"; + const entryPointAddressPimlico = "0xcaDBADcFeD5530A49762DFc9d1d712CcD6b09b25"; + const entryPointAddressMultiToken = + "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789"; + 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 bundlerUrlMultiToken = "https://testnet-rpc.etherspot.io/v1/28122024"; + const providerV06 = new providers.JsonRpcProvider(bundlerUrlV06); + const providerV07 = new providers.JsonRpcProvider(bundlerUrlV07); + const providerMultiToken = new providers.JsonRpcProvider( + bundlerUrlMultiToken + ); + const signerV06 = new Wallet(relayerKey, providerV06); + const signerV07 = new Wallet(relayerKey, providerV07); + const signerMultiToken = new Wallet(relayerKey, providerMultiToken); + + const userOpV06 = { + sender: "0x1434E767F0D878de8C053896ec6F7e5d1951eE00", + nonce: "0x0", + initCode: + "0x7f6d8f107fe8551160bd5351d5f1514a6ad5d40e5fbfb9cf0000000000000000000000009ae4935fae629dd042c18df520322e0e9efad73d0000000000000000000000000000000000000000000000000000000000000000", + callData: + "0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000009184e72a000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", + callGasLimit: "0xc7ed", + verificationGasLimit: "0x4d62f", + maxFeePerGas: "0x59682f1e", + maxPriorityFeePerGas: "0x59682f00", + paymasterAndData: "0x", + preVerificationGas: "0xb1f4", + signature: + "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c", + }; + + const userOpV07 = { + sender: "0x4040fC64C54FFD875F635D16ff2807a619AeFd69", + nonce: "0x4", + callData: + "0x541d63c800000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac00000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + callGasLimit: "0x0", + verificationGasLimit: "0x0", + preVerificationGas: "0x0", + maxFeePerGas: "0x85e0abb614", + maxPriorityFeePerGas: "0x85e0abb600", + signature: + "0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", }; - 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 UserOpMultiToken = { + sender: "0x1434E767F0D878de8C053896ec6F7e5d1951eE00", + nonce: "0x0", + initCode: + "0x7f6d8f107fe8551160bd5351d5f1514a6ad5d40e5fbfb9cf0000000000000000000000009ae4935fae629dd042c18df520322e0e9efad73d0000000000000000000000000000000000000000000000000000000000000000", + callData: + "0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000453478e2e0c846c069e544405d5877086960bef200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000e85649152d15825f2226b2d9c49c07b1cd2b36c700000000000000000000000000000000000000000000000000000000001e848000000000000000000000000000000000000000000000000000000000", + callGasLimit: "0xffb0", + verificationGasLimit: "0x4aa47", + maxFeePerGas: "0x596830f8", + maxPriorityFeePerGas: "0x59682f00", + preVerificationGas: "0xbef0", + paymasterAndData: "0x", + signature: + "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c", + }; + + test("SMOKE: validate the signV06 function with valid details", async () => { + await delay(3000); 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 signV06 action."); } }); - test('SMOKE: validate the pimlico function with valid details', async () => { - const gasToken = 'USDC'; + test("SMOKE: validate the signV07 function with valid details", async () => { + await delay(3000); 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" + ); } + try { + expect(signResponse).toHaveProperty("callGasLimit"); + } catch (e) { + throw new Error( + "The callGasLimit details is not displayed in the signV07 response" + ); + } + + try { + expect(signResponse).toHaveProperty("paymasterVerificationGasLimit"); + } catch (e) { + throw new Error( + "The paymasterVerificationGasLimit details is not displayed in the signV07 response" + ); + } + + try { + expect(signResponse).toHaveProperty("paymasterPostOpGasLimit"); + } catch (e) { + throw new Error( + "The paymasterPostOpGasLimit details is not displayed in the signV07 response" + ); + } } catch (e) { - fail('An error is displayed while using the pimlico function.') + throw new Error("An error is displayed while performing signV07 action."); } - }) + }); + + test("SMOKE: validate the getPaymasterAndDataForMultiTokenPaymaster function with valid details", async () => { + await delay(3000); + const paymasterContract = new ethers.Contract( + paymasterAddressMultiToken, + MultiTokenPaymasterAbi, + providerMultiToken + ); - test('SMOKE: validate the pimlicoAddress function with valid details', async () => { - const gasToken = 'USDC'; try { - const pimlicoAddressResponse = await paymaster.pimlicoAddress(gasToken, chainId); + await paymaster.getPaymasterAndDataForMultiTokenPaymaster( + UserOpMultiToken, + Mock_Valid_Until, + Mock_Valid_After, + feeTokenMultiToken, + ethPriceMultiToken, + paymasterContract, + signerMultiToken + ); + } catch (e) { + throw new Error( + "An error is displayed while performing getPaymasterAndDataForMultiTokenPaymaster action." + ); + } + }); + + test("SMOKE: validate the signMultiTokenPaymaster function with valid details", async () => { + await delay(3000); + try { + await paymaster.signMultiTokenPaymaster( + UserOpMultiToken, + Mock_Valid_Until, + Mock_Valid_After, + entryPointAddressMultiToken, + paymasterAddressMultiToken, + feeTokenMultiToken, + oracleAggregatorMultiToken, + bundlerUrlMultiToken, + signerMultiToken, + oracleNameMultiToken + ); + } catch (e) { + throw new Error( + "An error is displayed while performing signMultiTokenPaymaster action." + ); + } + }); + + test.skip("SMOKE: validate the pimlico function with valid details", async () => { + await delay(3000); + const chainId = "11155111"; + const gasToken = "USDC"; + try { + const tokenPaymasterAddress = PAYMASTER_ADDRESS[chainId][gasToken]; + const pimlicoResponse = await paymaster.pimlico( + userOpV06, + bundlerUrlPimlico, + entryPointAddressPimlico, + tokenPaymasterAddress + ); + + try { + expect(pimlicoResponse).toHaveProperty("paymasterAndData"); + } catch (e) { + throw new Error( + "The paymasterAndData details is not displayed in the pimlico response" + ); + } + + try { + expect(pimlicoResponse).toHaveProperty("verificationGasLimit"); + } catch (e) { + throw new Error( + "The verificationGasLimit details is not displayed in the pimlico response" + ); + } try { - expect(pimlicoAddressResponse).toHaveProperty('message'); + expect(pimlicoResponse).toHaveProperty("preVerificationGas"); } catch (e) { - fail("The message details is not displayed in the pimlico address response") + throw new Error( + "The preVerificationGas details is not displayed in the pimlico response" + ); } + try { + expect(pimlicoResponse).toHaveProperty("callGasLimit"); + } catch (e) { + throw new Error( + "The callGasLimit details is not displayed in the pimlico response" + ); + } } catch (e) { - fail('An error is displayed while using the pimlicoAddress function.') + throw new Error( + "An error is displayed while using the pimlico function." + ); + } + }); + + test("SMOKE: validate the pimlicoAddress function with valid details", async () => { + await delay(3000); + const chainId = 11155111; + const gasToken = "USDC"; + try { + 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) { + throw new Error( + "An error is displayed while using the pimlicoAddress function." + ); + } + }); + + test("SMOKE: validate the deposit function with epv06 details", async () => { + await delay(3000); + const amount = "0.0000001"; + try { + const depositResponse = await paymaster.deposit( + amount, + paymasterAddressV06, + bundlerUrlV06, + relayerKey, + chainId, + true + ); + + 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 { + throw new Error( + "The valid message is not displayed while performing the deposit action." + ); + } + } catch (e: any) { + throw new Error( + "An error is displayed while performing the deposit action." + ); } - }) + }); - test('SMOKE: validate the deposit function with valid details', async () => { - const amount = '0.0000001' + test("SMOKE: validate the deposit function with epv07 details", async () => { + await delay(3000); + const amount = "0.0000001"; try { - const depositResponse = await paymaster.deposit(amount, paymasterAddress, bundlerUrl, relayerKey, chainId); + const depositResponse = await paymaster.deposit( + amount, + paymasterAddressV07, + bundlerUrlV07, + relayerKey, + chainId, + false + ); const expectedMessage = depositResponse.message; - const actualMessage = 'Successfully deposited with transaction Hash'; + const actualMessage = "Successfully deposited with transaction Hash"; if (expectedMessage.includes(actualMessage)) { - console.log('The deposit function is working as expected.') + console.log("The deposit function is working as expected."); } else { - fail('The valid message is not displayed while performing the deposit action.') + throw new Error( + "The valid message is not displayed while performing the deposit action." + ); } } catch (e: any) { - fail('An error is displayed while performing the deposit action.') + throw new Error( + "An error is displayed while performing the deposit action." + ); } - }) + }); - test('REGRESSION: validate the sign function with invalid sender address detail', async () => { + test("REGRESSION: validate the signV06 function with invalid sender address detail", async () => { + await delay(3000); 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' + 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.sign(userOp, Mock_Valid_Until, Mock_Valid_After, entryPointAddress, paymasterAddress, bundlerUrl, signer); - fail('The sign function is worked, however the sender address 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 = + "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 { + throw new Error( + "The respective validation is not displayed for invalid sender address while using the sign function." + ); + } + } + }); + + test("REGRESSION: validate the signV06 function with estimation is false", async () => { + await delay(3000); + try { + const signResponse = await paymaster.signV06( + userOpV06, + Mock_Valid_Until, + Mock_Valid_After, + entryPointAddressV06, + paymasterAddressV06, + bundlerUrlV06, + signerV06, + false + ); + + try { + expect(signResponse).toHaveProperty("paymasterAndData"); + } catch (e) { + throw new Error( + "The paymasterAndData details is not displayed in the signV06 response" + ); + } + } catch (e) { + throw new Error("An error is displayed while performing signV06 action."); + } + }); + test("REGRESSION: validate the signV06 function with invalid bundler", async () => { + await delay(3000); + try { + await paymaster.signV06( + userOpV06, + Mock_Valid_Until, + Mock_Valid_After, + entryPointAddressV06, + paymasterAddressV06, + bundlerUrlV07, + signerV06, + true + ); } catch (e: any) { - const actualMessage = 'Please contact support team RawErrorMsg:invalid address'; + const actualMessage = + "Failed to process request to bundler. Please contact support team RawErrorMsg"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The sender address is invalid while using the sign function.') + console.log("The bundler is invalid while using the signV06 function."); } else { - fail('The respective validation is not displayed for invalid sender address while using the sign function.') + throw new Error( + "The respective validation is not displayed for invalid bundler while using the signV06 function." + ); + } + } + }); + + test("REGRESSION: validate the signV07 function with estimation is false", async () => { + await delay(3000); + try { + const signResponse = await paymaster.signV07( + userOpV07, + Mock_Valid_Until, + Mock_Valid_After, + entryPointAddressV07, + paymasterAddressV07, + bundlerUrlV07, + signerV07, + false + ); + + try { + expect(signResponse).toHaveProperty("paymaster"); + } catch (e) { + throw new Error( + "The paymaster details is not displayed in the signV07 response" + ); + } + + try { + expect(signResponse).toHaveProperty("paymasterData"); + } catch (e) { + throw new Error( + "The paymasterData 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 signV07 function with invalid bundler", async () => { + await delay(3000); + try { + await paymaster.signV07( + userOpV07, + Mock_Valid_Until, + Mock_Valid_After, + entryPointAddressV07, + paymasterAddressV07, + bundlerUrlV06, + signerV07, + true + ); + } catch (e: any) { + const actualMessage = + "Failed to process request to bundler. Please contact support team RawErrorMsg"; + const expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + console.log("The bundler is invalid while using the signv07 function."); + } else { + throw new Error( + "The respective validation is not displayed for invalid bundler while using the signv07 function." + ); + } + } }); - test('REGRESSION: validate the pimlico function with invalid custom paymaster address', async () => { - const gasToken = 'USDC'; + test.skip("REGRESSION: validate the pimlico function with invalid custom paymaster address", async () => { + await delay(3000); + const gasToken = "USDC"; const address = ethers.Wallet.createRandom(); // random address try { - await paymaster.pimlico(userOp, bundlerUrl, entryPointAddress, address.toString()); // invalid custom paymaster address - fail('The pimlico function is worked, however the customPaymasterAddress is invalid.') + 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 = 'Please contact support team RawErrorMsg: network does not support ENS'; + const actualMessage = + "Please contact support team RawErrorMsg: network does not support ENS"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The customPaymasterAddress is invalid while using the pimlico function.') + 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.') + throw new Error( + "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'; + test.skip("REGRESSION: validate the pimlico function with invalid sender address", async () => { + await delay(3000); + 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' + 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, bundlerUrl, entryPointAddress, PAYMASTER_ADDRESS[chainId][gasToken]); - fail('The pimlico function is worked, however the sender address is invalid.') + 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 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.') + 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.') + 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 () => { + test("REGRESSION: validate the whitelistAddresses function with not whitelisted address", async () => { + await delay(3000); const wallet = ethers.Wallet.createRandom(); const address = [wallet.address]; // not whitelisted address try { - const whitelistAddresses = await paymaster.whitelistAddresses(address, paymasterAddress, bundlerUrl, relayerKey, chainId); + 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.') + 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.') + throw new Error( + "The expected success message is not displayed while performing the whitelistAddress action." + ); } } catch (e: any) { - fail('An error is displayed while performing the whitelistAddress action.') + 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 + test("REGRESSION: validate the whitelistAddresses function with already whitelisted address", async () => { + await delay(3000); + const address = ["0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321"]; // already whitelisted address try { - await paymaster.whitelistAddresses(address, paymasterAddress, bundlerUrl, relayerKey, chainId); - fail('Address is whitelisted, However it was already whitelisted.') + 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 actualMessage = "already whitelisted"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The address is already whitelisted.') + console.log("The address is already whitelisted."); } else { - fail('The respective validation is not displayed for already whitelisted address. ') + 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 + test("REGRESSION: validate the whitelistAddresses function with invalid relayerKey", async () => { + await delay(3000); + const address = ["0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321"]; // already whitelisted address + const relayerKey = + "0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb"; // invalid relayerKey try { - await paymaster.whitelistAddresses(address, paymasterAddress, bundlerUrl, relayerKey, chainId); - fail('Address is whitelisted, however the relayerKey is invalid.') + 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 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.') + console.log( + "The relayerKey is invalid while whitelisting the address." + ); } else { - fail('The respective validation is not displayed for invalid relayerKey while address whitelisting.') + 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 + test("REGRESSION: validate the checkWhitelistAddress function with whitelisted address", async () => { + await delay(3000); + const address = "0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321"; // whitelisted address try { - const checkWhitelistAddressResponse = await paymaster.checkWhitelistAddress(address, paymasterAddress, bundlerUrl, relayerKey); + const checkWhitelistAddressResponse = + await paymaster.checkWhitelistAddress( + address, + paymasterAddressV06, + bundlerUrlV06, + relayerKey + ); if (checkWhitelistAddressResponse === true) { - console.log('The address is whitelisted.') + console.log("The address is whitelisted."); } else { - fail('The address is displayed not whitelisted, however it is already whitelisted.') + throw new Error( + "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.') - + 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 + test("REGRESSION: validate the checkWhitelistAddress function with non whitelisted address", async () => { + await delay(3000); + const address = "0x8350355c08aDAC387b443782124A30A8942BeC2e"; // non whitelisted address try { - const checkWhitelistAddressResponse = await paymaster.checkWhitelistAddress(address, paymasterAddress, bundlerUrl, relayerKey); + const checkWhitelistAddressResponse = + await paymaster.checkWhitelistAddress( + address, + paymasterAddressV06, + bundlerUrlV06, + relayerKey + ); if (checkWhitelistAddressResponse === false) { - console.log('The address is not whitelisted as expected.') + 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 () => { + await delay(3000); + 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 removeWhitelistAddress function with not whitelisted address", async () => { + await delay(3000); + let wallet = ethers.Wallet.createRandom(); + let address = [wallet.address]; // not whitelisted address + + // make the address whitelisted + 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." + ); + } + + // wait for 10 second + await delay(10000); + + // remove the address from the whitelisting + try { + const removeWhitelistAddress = await paymaster.removeWhitelistAddress( + address, + paymasterAddressV06, + bundlerUrlV06, + relayerKey, + chainId + ); + + if ( + removeWhitelistAddress.message.includes( + "Successfully removed whitelisted addresses" + ) + ) { + console.log( + "The address is removed from the whitelisting successfully." + ); + } else { + throw new Error( + "The expected success message is not displayed while performing the removeWhitelistAddress action." + ); + } + } catch (e: any) { + throw new Error( + "An error is displayed while performing the whitelistAddress action." + ); + } + }); + + test("REGRESSION: validate the removeWhitelistAddress function with already removed from whitelisted address", async () => { + await delay(3000); + let wallet = ethers.Wallet.createRandom(); + let address = [wallet.address]; // not whitelisted address + + // make the address whitelisted + try { + await paymaster.whitelistAddresses( + address, + paymasterAddressV06, + bundlerUrlV06, + relayerKey, + chainId + ); + } catch (e: any) { + console.log("error 1:::::::::", e); + throw new Error( + "An error is displayed while performing the whitelistAddress action." + ); + } + + // wait for 10 second + await delay(10000); + + // remove the address from the whitelisting + try { + await paymaster.removeWhitelistAddress( + address, + paymasterAddressV06, + bundlerUrlV06, + relayerKey, + chainId + ); + } catch (e: any) { + console.log("error 2:::::::::", e); + throw new Error( + "An error is displayed while performing the removeWhitelistAddress action." + ); + } + + // wait for 5 second + await delay(5000); + + // again trying for removing address from whitelisting + try { + await paymaster.removeWhitelistAddress( + address, + paymasterAddressV06, + bundlerUrlV06, + relayerKey, + chainId + ); + throw new Error( + "Address is removed from the whitelisting, However it was already removed from the whitelisting." + ); + } catch (e: any) { + console.log("error 3:::::::::", e); + const actualMessage = "is not whitelisted"; + const expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + console.log("The address is already removed from the whitelisting."); + } else { + throw new Error( + "The respective validation is not displayed for already removed the address from whitelisting. " + ); + } + } + }); + + test("REGRESSION: validate the removeWhitelistAddress function with invalid relayerKey", async () => { + await delay(3000); + let wallet = ethers.Wallet.createRandom(); + let address = [wallet.address]; // not whitelisted address + const relayerKey = + "0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb2"; // valid relayerKey + const relayerKey_invalid = + "0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb"; // invalid relayerKey + + // make the address whitelisted + try { + await paymaster.whitelistAddresses( + address, + paymasterAddressV06, + bundlerUrlV06, + relayerKey, + chainId + ); + } catch (e: any) { + console.log("error 1:::::::::", e); + throw new Error( + "An error is displayed while performing the whitelistAddress action." + ); + } + + // wait for 10 second + await delay(10000); + + // remove the address from the whitelisting + try { + await paymaster.removeWhitelistAddress( + address, + paymasterAddressV06, + bundlerUrlV06, + relayerKey_invalid, + chainId + ); + throw new Error( + "The removeWhitelistAddress action is performed with invalid relayerKey." + ); + } catch (e: any) { + console.log("error 2:::::::::", e); + const actualMessage = + "The wallet does not have enough funds or the gas price is too high at the moment."; + const expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + console.log( + "The relayerKey is invalid while perform the removing the address from the whitelisting." + ); } else { - fail('The address is displayed whitelisted, however it is not whitelisted.') + throw new Error( + "The respective validation is not displayed for invalid relayerKey while perform the removing the address from the whitelisting." + ); } + } + }); + + test("REGRESSION: validate the deposit function with exceeded amount", async () => { + await delay(3000); + const amount = "10000000"; // exceeded amount + try { + await paymaster.deposit( + amount, + paymasterAddressV06, + bundlerUrlV06, + relayerKey, + chainId, + true + ); + throw new Error("The deposite action is performed with exceeded amount."); } catch (e: any) { - fail('An error is displayed while checking the address for whitelisting.') + const actualMessage = "Balance is less than the amount to be deposited"; + const expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + console.log("The amount is exceeded while performing the deposit."); + } else { + throw new Error( + "The respective validation is not displayed for exceeded amount while deposit." + ); + } } - }) + }); - test('REGRESSION: validate the checkWhitelistAddress function with invalid relayerKey', async () => { - const address = '0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321'; - const relayerKey = '0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb'; // invalid relayerKey + test("REGRESSION: validate the deposit function with invalid amount", async () => { + await delay(3000); + const amount = "abc"; // invalid amount try { - await paymaster.checkWhitelistAddress(address, paymasterAddress, bundlerUrl, relayerKey); - fail('The whitelist address checking is performed, however the relayerKey is invalid.') + await paymaster.deposit( + amount, + paymasterAddressV06, + bundlerUrlV06, + relayerKey, + chainId, + true + ); + throw new Error("The deposite action is performed with invalid amount."); } catch (e: any) { - const actualMessage = 'rpcError while checking whitelist'; + console.log("error 1:::::::::", e); + const actualMessage = + "The wallet does not have enough funds or the gas price is too high at the moment."; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The relayerKey is invalid while checking the whitelist address.') + console.log("The amount is invalid while performing the deposit."); } 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 amount while deposit." + ); } } - }) + }); - test('REGRESSION: validate the deposit function with invalid amount', async () => { - const amount = '10000' // invalid amount + test("REGRESSION: validate the signV06 function with multiTokenMarkUp is NaN", async () => { + await delay(3000); + const paymaster1 = new Paymaster("0", "NaN"); try { - await paymaster.deposit(amount, paymasterAddress, bundlerUrl, relayerKey, chainId); - fail('The deposite action is performed with invalid amount.') + const signResponse = await paymaster1.signV06( + userOpV06, + Mock_Valid_Until, + Mock_Valid_After, + entryPointAddressV06, + paymasterAddressV06, + bundlerUrlV06, + signerV06, + true + ); + + try { + expect(signResponse).toHaveProperty("paymasterAndData"); + } catch (e) { + throw new Error( + "The paymasterAndData details is not displayed in the signV06 response" + ); + } + + try { + expect(signResponse).toHaveProperty("verificationGasLimit"); + } catch (e) { + throw new Error( + "The verificationGasLimit details is not displayed in the signV06 response" + ); + } + + try { + expect(signResponse).toHaveProperty("preVerificationGas"); + } catch (e) { + throw new Error( + "The preVerificationGas details is not displayed in the signV06 response" + ); + } + + try { + expect(signResponse).toHaveProperty("callGasLimit"); + } catch (e) { + throw new Error( + "The callGasLimit details is not displayed in the signV06 response" + ); + } + } catch (e) { + throw new Error("An error is displayed while performing signV06 action."); + } + }); + + test("REGRESSION: validate the signMultiTokenPaymaster function with valid details", async () => { + await delay(3000); + try { + await paymaster.signMultiTokenPaymaster( + UserOpMultiToken, + Mock_Valid_Until, + Mock_Valid_After, + entryPointAddressMultiToken, + paymasterAddressMultiToken, + feeTokenMultiToken, + oracleAggregatorMultiToken, + bundlerUrlMultiToken, + signerMultiToken, + "chainlink" + ); } catch (e: any) { - const actualMessage = 'Balance is less than the amount to be deposited'; + const actualMessage = + "Failed to process request to bundler. Please contact support team RawErrorMsg"; const expectedMessage = e.message; if (expectedMessage.includes(actualMessage)) { - console.log('The amount is invalid while performing the deposit.') + console.log( + "The oraclename is invalid while performing the signMultiTokenPaymaster." + ); } else { - fail('The respective validation is not displayed for invalid amount while deposit.') + throw new Error( + "The respective validation is not displayed for invalid oraclename while signMultiTokenPaymaster." + ); } } - }) -}); \ No newline at end of file + }); + + test("REGRESSION: validate the pimlicoAddress function with invalid chainid", async () => { + await delay(3000); + const chainId = 1115511; // invalid chainid + const gasToken = "USDC"; + try { + await paymaster.pimlicoAddress(gasToken, chainId); + } catch (e: any) { + const actualMessage = "Cannot read properties of undefined"; + const expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + console.log( + "The chainid is invalid while performing the pimlicoAddress." + ); + } else { + throw new Error( + "The respective validation is not displayed for invalid chainid while pimlicoAddress." + ); + } + } + }); +}); 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/routes/index.ts b/backend/src/routes/index.ts index 2e467a1..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, true, 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, false, 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 {