diff --git a/backend/jest.config.js b/backend/jest.config.js index 6c1e9ae..9200cd9 100644 --- a/backend/jest.config.js +++ b/backend/jest.config.js @@ -1,5 +1,39 @@ /** @type {import('ts-jest').JestConfigWithTsJest} */ export default { - preset: 'ts-jest', + preset: 'ts-jest/presets/js-with-ts-esm', + moduleNameMapper: { + '^(\\.{1,2}/.*)\\.js$': '$1', + }, testEnvironment: 'node', -}; \ No newline at end of file + transform: { + '^.+\\.ts?$': [ + 'ts-jest', + { + useESM: true, + }, + ], + }, + transformIgnorePatterns: [ + 'node_modules/(?!(data-uri-to-buffer|formdata-polyfill|fetch-blob|node-fetch)/)', + ], + testPathIgnorePatterns: [ + '/node_modules/', + '/build/' + ], + resetModules: true, + testTimeout: 30000, + coverageThreshold: { + global: { + statements: 95, + branches: 75, + functions: 100, + lines: 95, + }, + }, + coveragePathIgnorePatterns: [ + 'src/server.ts', + 'src/plugins/config.ts', + ], + collectCoverage: true, + coverageReporters: ["lcov", "text"] +} \ No newline at end of file diff --git a/backend/src/paymaster/index.test.ts b/backend/src/paymaster/index.test.ts new file mode 100644 index 0000000..a9e1524 --- /dev/null +++ b/backend/src/paymaster/index.test.ts @@ -0,0 +1,334 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { ethers, Wallet } from "ethers"; +import { Paymaster } from "./index.js"; + +describe('Paymaster on Mumbai', () => { + const paymaster = new Paymaster(); + const paymasterAddress = '0x8350355c08aDAC387b443782124A30A8942BeC2e'; // Mumbai Etherspot Paymaster Address + const entryPointAddress = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"; // EntryPoint v0.6 as default + const bundlerUrl = 'https://mumbai-bundler.etherspot.io'; + const relayerKey = '0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb2'; // Testing wallet private key only has Mumbai funds in it + const userOp = { + sender: '0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321', + nonce: '0x1', + initCode: '0x', + callData: '0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000', + callGasLimit: '0x88b8', + verificationGasLimit: '0x186a0', + maxFeePerGas: '0x6fc23ac10', + maxPriorityFeePerGas: '0x6fc23ac00', + paymasterAndData: '0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', + signature: '0x0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', + preVerificationGas: '0xc6c4' + }; + + test('SMOKE: validate the sign function with valid details', async () => { + const Mock_Valid_Until = '0x00000000deadbeef'; // max value + const Mock_Valid_After = '0x0000000000001234'; // min value + try { + const signResponse = await paymaster.sign(userOp, Mock_Valid_Until, Mock_Valid_After, entryPointAddress, paymasterAddress, bundlerUrl, relayerKey); + + try { + expect(signResponse).toHaveProperty('paymasterAndData'); + } catch (e) { + fail("The paymasterAndData details is not displayed in the sign response") + } + + try { + expect(signResponse).toHaveProperty('verificationGasLimit'); + } catch (e) { + fail("The verificationGasLimit details is not displayed in the sign response") + } + + try { + expect(signResponse).toHaveProperty('preVerificationGas'); + } catch (e) { + fail("The preVerificationGas details is not displayed in the sign response") + } + + try { + expect(signResponse).toHaveProperty('callGasLimit'); + } catch (e) { + fail("The callGasLimit details is not displayed in the sign response") + } + } catch (e) { + fail('An error is displayed while performing sign action.') + } + }); + + test('SMOKE: validate the pimlico function with valid details', async () => { + const gasToken = 'USDC'; + try { + const pimlicoResponse = await paymaster.pimlico(userOp, gasToken, bundlerUrl, entryPointAddress, null); + + try { + expect(pimlicoResponse).toHaveProperty('paymasterAndData'); + } catch (e) { + fail("The paymasterAndData details is not displayed in the pimlico response") + } + + try { + expect(pimlicoResponse).toHaveProperty('verificationGasLimit'); + } catch (e) { + fail("The verificationGasLimit details is not displayed in the pimlico response") + } + + try { + expect(pimlicoResponse).toHaveProperty('preVerificationGas'); + } catch (e) { + fail("The preVerificationGas details is not displayed in the pimlico response") + } + + try { + expect(pimlicoResponse).toHaveProperty('callGasLimit'); + } catch (e) { + fail("The callGasLimit details is not displayed in the pimlico response") + } + + } catch (e) { + fail('An error is displayed while using the pimlico function.') + } + }) + + test('SMOKE: validate the pimlicoAddress function with valid details', async () => { + const gasToken = 'USDC'; + try { + const pimlicoAddressResponse = await paymaster.pimlicoAddress(gasToken, bundlerUrl, entryPointAddress); + + try { + expect(pimlicoAddressResponse).toHaveProperty('message'); + } catch (e) { + fail("The message details is not displayed in the pimlico address response") + } + + } catch (e) { + fail('An error is displayed while using the pimlicoAddress function.') + } + }) + + test('SMOKE: validate the deposit function with valid details', async () => { + const amount = '0.0000001' + try { + const depositResponse = await paymaster.deposit(amount, paymasterAddress, bundlerUrl, relayerKey); + + const expectedMessage = depositResponse.message; + const actualMessage = 'Successfully deposited with transaction Hash'; + + if (expectedMessage.includes(actualMessage)) { + console.log('The deposit function is working as expected.') + } else { + fail('The valid message is not displayed while performing the deposit action.') + } + } catch (e: any) { + fail('An error is displayed while performing the deposit action.') + } + }) + + test('REGRESSION: validate the sign function with invalid sender address detail', async () => { + const userOp = { + sender: '0x7b3078b9A28DF76453CDfD2bA5E75f32f067632', // invalid sender address + nonce: '0x1', + initCode: '0x', + callData: '0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000', + callGasLimit: '0x88b8', + verificationGasLimit: '0x186a0', + maxFeePerGas: '0x6fc23ac10', + maxPriorityFeePerGas: '0x6fc23ac00', + paymasterAndData: '0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', + signature: '0x0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', + preVerificationGas: '0xc6c4' + }; + + const Mock_Valid_Until = '0x00000000deadbeef'; + const Mock_Valid_After = '0x0000000000001234'; + try { + await paymaster.sign(userOp, Mock_Valid_Until, Mock_Valid_After, entryPointAddress, paymasterAddress, bundlerUrl, relayerKey); + fail('The sign function is worked, however the sender address is invalid.') + + } catch (e: any) { + const actualMessage = 'Transaction Execution reverted'; + const expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + console.log('The sender address is invalid while using the sign function.') + } else { + fail('The respective validation is not displayed for invalid sender address while using the sign function.') + } + } + + }); + + test('REGRESSION: validate the pimlico function with invalid custom paymaster address', async () => { + const gasToken = 'USDC'; + const address = ethers.Wallet.createRandom(); // random address + try { + await paymaster.pimlico(userOp, gasToken, bundlerUrl, entryPointAddress, address.toString()); // invalid custom paymaster address + fail('The pimlico function is worked, however the customPaymasterAddress is invalid.') + } catch (e: any) { + const actualMessage = 'Transaction Execution reverted network does not support ENS'; + const expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + console.log('The customPaymasterAddress is invalid while using the pimlico function.') + } else { + fail('The respective validation is not displayed for invalid customPaymasterAddress while using the pimlico function.') + } + } + }) + + test('REGRESSION: validate the pimlico function with invalid sender address', async () => { + const gasToken = 'USDC'; + const userOp = { + sender: '0x7b3078b9A28DF76453CDfD2bA5E75f32f067632', // invalid address + nonce: '0x1', + initCode: '0x', + callData: '0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000', + callGasLimit: '0x88b8', + verificationGasLimit: '0x186a0', + maxFeePerGas: '0x6fc23ac10', + maxPriorityFeePerGas: '0x6fc23ac00', + paymasterAndData: '0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', + signature: '0x0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', + preVerificationGas: '0xc6c4' + }; + + try { + await paymaster.pimlico(userOp, gasToken, bundlerUrl, entryPointAddress, null); + fail('The pimlico function is worked, however the sender address is invalid.') + } catch (e: any) { + const actualMessage = 'Transaction Execution reverted'; + const expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + console.log('The sender address is invalid while using the pimlico function.') + } else { + fail('The respective validation is not displayed for invalid sender address while using the pimlico function.') + } + } + }) + + test('REGRESSION: validate the pimlicoAddress function with invalid bundlerUrl', async () => { + const gasToken = 'USDC'; + const bundlerUrl = 'http://mumbai-bundler.etherspot.io'; // invalid bundlerUrl + try { + await paymaster.pimlicoAddress(gasToken, bundlerUrl, entryPointAddress); + fail('The pimlicoAddress function is worked, however the bundlerUrl is invalid.') + } catch (e: any) { + const actualMessage = 'could not detect network'; + const expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + console.log('The bundlerUrl is invalid while using the pimlicoAddress function.') + } else { + fail('The respective validation is not displayed for invalid bundlerUrl while using the pimlicoAddress function.') + } + } + }) + + test('REGRESSION: validate the whitelistAddresses function with not whitelisted address', async () => { + const wallet = ethers.Wallet.createRandom(); + const address = [wallet.address]; // not whitelisted address + try { + const whitelistAddresses = await paymaster.whitelistAddresses(address, paymasterAddress, bundlerUrl, relayerKey); + + 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.') + } + } catch (e: any) { + fail('An error is displayed while performing the whitelistAddress action.') + } + }) + + test('REGRESSION: validate the whitelistAddresses function with already whitelisted address', async () => { + const address = ['0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321']; // already whitelisted address + try { + await paymaster.whitelistAddresses(address, paymasterAddress, bundlerUrl, relayerKey); + fail('Address is whitelisted, However it was already whitelisted.') + } catch (e: any) { + const actualMessage = 'already whitelisted'; + const expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + console.log('The address is already whitelisted.') + } else { + fail('The respective validation is not displayed for already whitelisted address. ') + } + } + }) + + test('REGRESSION: validate the whitelistAddresses function with invalid relayerKey', async () => { + const address = ['0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321']; // already whitelisted address + const relayerKey = '0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb'; // invalid relayerKey + try { + await paymaster.whitelistAddresses(address, paymasterAddress, bundlerUrl, relayerKey); + fail('Address is whitelisted, however the relayerKey is invalid.') + } catch (e: any) { + const actualMessage = 'Error while submitting transaction'; + const expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + console.log('The relayerKey is invalid while whitelisting the address.') + } else { + fail('The respective validation is not displayed for invalid relayerKey while address whitelisting.') + } + } + }) + + test('REGRESSION: validate the checkWhitelistAddress function with whitelisted address', async () => { + const address = '0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321'; // whitelisted address + try { + const checkWhitelistAddressResponse = await paymaster.checkWhitelistAddress(address, paymasterAddress, bundlerUrl, relayerKey); + if (checkWhitelistAddressResponse === true) { + console.log('The address is whitelisted.') + } else { + fail('The address is displayed not whitelisted, however it is already whitelisted.') + } + } catch (e: any) { + fail('An error is displayed while checking the address for whitelisting.') + + } + }) + + test('REGRESSION: validate the checkWhitelistAddress function with non whitelisted address', async () => { + const address = '0x8350355c08aDAC387b443782124A30A8942BeC2e'; // non whitelisted address + try { + const checkWhitelistAddressResponse = await paymaster.checkWhitelistAddress(address, paymasterAddress, bundlerUrl, relayerKey); + if (checkWhitelistAddressResponse === false) { + console.log('The address is not whitelisted as expected.') + } else { + fail('The address is displayed whitelisted, however it is not whitelisted.') + } + } catch (e: any) { + fail('An error is displayed while checking the address for whitelisting.') + } + }) + + test('REGRESSION: validate the checkWhitelistAddress function with invalid relayerKey', async () => { + const address = '0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321'; + const relayerKey = '0xdd45837c9d94e7cc3ed3b24be7c1951eff6ed3c6fd0baf68fc1ba8c0e51debb'; // invalid relayerKey + try { + await paymaster.checkWhitelistAddress(address, paymasterAddress, bundlerUrl, relayerKey); + fail('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 { + fail('The respective validation is not displayed for invalid relayerKey while checking the whitelist address.') + } + } + }) + + test('REGRESSION: validate the deposit function with invalid amount', async () => { + const amount = '10000' // invalid amount + try { + await paymaster.deposit(amount, paymasterAddress, bundlerUrl, relayerKey); + fail('The deposite action is performed with invalid amount.') + } catch (e: any) { + const actualMessage = 'Error while submitting transaction'; + const expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + console.log('The amount is invalid while performing the deposit.') + } else { + fail('The respective validation is not displayed for invalid amount while deposit.') + } + } + }) +}); \ No newline at end of file diff --git a/backend/src/paymaster/index.ts b/backend/src/paymaster/index.ts index 4208fe2..d5ff444 100644 --- a/backend/src/paymaster/index.ts +++ b/backend/src/paymaster/index.ts @@ -59,7 +59,7 @@ export class Paymaster { } } - async pimlico(userOp: any, gasToken: string, bundlerRpc: string, entryPoint: string, customPaymasterAddress: string) { + async pimlico(userOp: any, gasToken: string, bundlerRpc: string, entryPoint: string, customPaymasterAddress: string | null) { try { const provider = new providers.JsonRpcProvider(bundlerRpc); let erc20Paymaster; diff --git a/backend/src/paymaster/pimlico.test.ts b/backend/src/paymaster/pimlico.test.ts new file mode 100644 index 0000000..d83e0a4 --- /dev/null +++ b/backend/src/paymaster/pimlico.test.ts @@ -0,0 +1,349 @@ +/* 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"; + +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 userOp = { + sender: '0x7b3078b9A28DF76453CDfD2bA5E75f32f0676321', + nonce: '0x1', + initCode: '0x', + callData: '0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000', + callGasLimit: '0x88b8', + verificationGasLimit: '0x186a0', + maxFeePerGas: '0x6fc23ac10', + maxPriorityFeePerGas: '0x6fc23ac00', + paymasterAndData: '0x0101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000001010101010100000000000000000000000000000000000000000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', + signature: '0x0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101', + preVerificationGas: '0xc6c4' + }; + + const ERC20PaymasterBuildOptions = { + entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + nativeAsset: NATIVE_ASSET[80001], + nativeAssetOracle: ORACLE_ADDRESS[80001].MATIC, + tokenAddress: TOKEN_ADDRESS[80001].USDC, + tokenOracle: ORACLE_ADDRESS[80001].USDC, + owner: "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 () => { + try { + const calculateTokenAmountResponse = await pimlicoPaymaster.calculateTokenAmount(userOp); + + try { + expect(calculateTokenAmountResponse).toHaveProperty('_hex'); + } catch (e) { + fail("The _hex details is not displayed in the calculate token amount response") + } + + } catch (e) { + fail('An error is displayed while performing calculateTokenAmount action.') + } + }); + + test('SMOKE: validate the generatePaymasterAndData function with valid details', async () => { + try { + const generatePaymasterAndDataResponse = await pimlicoPaymaster.generatePaymasterAndData(userOp); + try { + expect(generatePaymasterAndDataResponse.length.toString()).toMatch('106'); + } catch (e) { + fail("The paymaster and data details is not displayed in the generatePaymasterAndData response") + } + } catch (e) { + fail('An error is displayed while performing generatePaymasterAndData action.') + } + }); + + test('SMOKE: validate the getERC20Paymaster function with valid details', async () => { + const erc20 = 'USDC'; + try { + const getERC20PaymasterResponse = await getERC20Paymaster(provider, erc20, entryPointAddress); + + try { + expect(getERC20PaymasterResponse).toHaveProperty('paymasterAddress'); + } catch (e) { + fail("The paymasterAddress details is not displayed in the getERC20Paymaster response") + } + } catch (e) { + 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'; + try { + const getERC20PaymasterResponse = await getERC20Paymaster(provider, erc20, entryPointAddress, ERC20PaymasterBuildOptions); + + try { + expect(getERC20PaymasterResponse).toHaveProperty('paymasterAddress'); + } catch (e) { + fail("The paymasterAddress details is not displayed in the getERC20Paymaster response") + } + + } catch (e) { + fail('An error is displayed while performing getERC20Paymaster action.') + } + }); + + test('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" + } + try { + 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 expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + 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.') + } + } + }); + + test('REGRESSION: validate the getERC20Paymaster function with without deployer', 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, + owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", + } + try { + 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 expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + 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.') + } + } + }); + + test('REGRESSION: validate the getERC20Paymaster function with invalid native asset', async () => { + const erc20 = 'USDC'; + const ERC20PaymasterBuildOptions = { + entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + nativeAsset: "", + nativeAssetOracle: ORACLE_ADDRESS[80001].MATIC, + tokenAddress: TOKEN_ADDRESS[80001].USDC, + tokenOracle: ORACLE_ADDRESS[80001].USDC, + owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680" + } + try { + 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 expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + 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.') + } + } + }); + + test('REGRESSION: validate the getERC20Paymaster function with invalid native asset oracle', async () => { + const erc20 = 'USDC'; + const ERC20PaymasterBuildOptions = { + entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + nativeAsset: "80002", + nativeAssetOracle: ORACLE_ADDRESS[80001].ETH, + tokenAddress: TOKEN_ADDRESS[80001].USDC, + tokenOracle: ORACLE_ADDRESS[80001].USDC, + owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680" + } + try { + 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 expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + 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.') + } + } + }); + + test('REGRESSION: validate the getERC20Paymaster function with native asset oracle not deployed', async () => { + const randomAddress = ethers.Wallet.createRandom(); + const erc20 = 'USDC'; + const ERC20PaymasterBuildOptions = { + entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + nativeAsset: NATIVE_ASSET[80001], + nativeAssetOracle: randomAddress.address, + tokenAddress: TOKEN_ADDRESS[80001].USDC, + tokenOracle: ORACLE_ADDRESS[80001].USDC, + owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8680" + } + try { + 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 expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + 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.') + } + } + }); + + test('REGRESSION: validate the getERC20Paymaster function with invalid token address', async () => { + const erc20 = 'USDC'; + const ERC20PaymasterBuildOptions = { + entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + nativeAsset: NATIVE_ASSET[80001], + nnativeAssetOracle: ORACLE_ADDRESS[80001].MATIC, + tokenAddress: "", + tokenOracle: ORACLE_ADDRESS[80001].USDC, + owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8685" + } + try { + 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 expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + 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.') + } + } + }); + + test('REGRESSION: validate the getERC20Paymaster function with token address not deployed', async () => { + const randomAddress = ethers.Wallet.createRandom(); + const erc20 = 'USDC'; + const ERC20PaymasterBuildOptions = { + entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + nativeAsset: NATIVE_ASSET[80001], + nnativeAssetOracle: ORACLE_ADDRESS[80001].MATIC, + tokenAddress: randomAddress.address, + tokenOracle: ORACLE_ADDRESS[80001].USDC, + owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8685" + } + try { + 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 expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + 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.') + } + } + }); + + test('REGRESSION: validate the getERC20Paymaster function with invalid token oracle', async () => { + const erc20 = 'USDC'; + const ERC20PaymasterBuildOptions = { + entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + nativeAsset: NATIVE_ASSET[80001], + nnativeAssetOracle: ORACLE_ADDRESS[80001].MATIC, + tokenAddress: ORACLE_ADDRESS[80001].USDC, + tokenOracle: "", + owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8685" + } + try { + 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 expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + 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.') + } + } + }); + + test('REGRESSION: validate the getERC20Paymaster function with token oracle not deployed', async () => { + const randomAddress = ethers.Wallet.createRandom(); + const erc20 = 'USDC'; + const ERC20PaymasterBuildOptions = { + entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + nativeAsset: NATIVE_ASSET[80001], + nnativeAssetOracle: ORACLE_ADDRESS[80001].MATIC, + tokenAddress: ORACLE_ADDRESS[80001].USDC, + tokenOracle: randomAddress.address, + owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", + deployer: "0x4337000c2828f5260d8921fd25829f606b9e8685" + } + try { + 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 expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + 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.') + } + } + }); + + test('REGRESSION: validate the getERC20Paymaster function with ERC20Paymaster not deployed', async () => { + const randomAddress = ethers.Wallet.createRandom(); + const erc20 = 'USDC'; + const ERC20PaymasterBuildOptions = { + entrypoint: "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + nativeAsset: NATIVE_ASSET[80001], + nnativeAssetOracle: ORACLE_ADDRESS[80001].MATIC, + tokenAddress: ORACLE_ADDRESS[80001].USDC, + tokenOracle: ORACLE_ADDRESS[80001].USDC, + owner: "0x4337000c2828f5260d8921fd25829f606b9e8680", + deployer: randomAddress + } + try { + 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 expectedMessage = e.message; + if (expectedMessage.includes(actualMessage)) { + 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.') + } + } + }); +}); \ No newline at end of file diff --git a/backend/test/helper.ts b/backend/test/helper.ts deleted file mode 100644 index 43f9263..0000000 --- a/backend/test/helper.ts +++ /dev/null @@ -1,29 +0,0 @@ -import fastify from 'Fastify'; -import fp from 'fastify-plugin'; -import { configPlugin } from '../src/plugins/config'; -import routes from '../src/routes/index' - - -// Automatically build and tear down our instance -function build () { - const app = fastify(); - - // fastify-plugin ensures that all decorators - // are exposed for testing purposes, this is - // different from the production setup - - - beforeAll(async () => { - void app.register(fp(configPlugin)); - app.register(routes) - await app.ready(); - }); - - afterAll(() => app.close()) - - return app -} - -export { - build -} \ No newline at end of file diff --git a/backend/test/routes.test.ts b/backend/test/routes.test.ts deleted file mode 100644 index 7ff5845..0000000 --- a/backend/test/routes.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { build } from './helper' - -describe('root tests', () => { - const app = build(); - -test('default root route without params', async () => { - const res = await app.inject({ - url: '/', - method: "POST" - }) - expect(JSON.parse(res.payload)).toEqual({ error: 'Empty Body received'}) -}) - -test('default etherspot paymaster with params', async () => { - const userOp = { - sender: "0x603Ef162f05dDa6e3B4717f4A951d6eF614a897f", - nonce: "0x1d", - initCode: "0x", - callData: "0x47e1da2a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000080a1874e1046b1cc5defdf4d3153838b72ff94ac0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000002386f26fc10000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", - callGasLimit: "0x8342", - verificationGasLimit: "0x16070", - maxFeePerGas: "0x7d912eba", - maxPriorityFeePerGas: "0x7d912eaa", - paymasterAndData: "0x", - preVerificationGas: "0xa96c", - signature: "0x" - }; - const res = await app.inject({ - url: '/', - method: "POST", - payload: {params: [userOp, "0x603Ef162f05dDa6e3B4717f4A951d6eF614a897f"]}, - }); - expect(res.statusCode).toEqual(200); - expect(JSON.parse(res.payload)).toHaveProperty('paymasterAndData'); -}) - -}) \ No newline at end of file diff --git a/backend/test/tsconfig.test.json b/backend/test/tsconfig.test.json deleted file mode 100644 index 87e1081..0000000 --- a/backend/test/tsconfig.test.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": "./", - "resolvePackageJsonImports": true, - "rootDir": "./", - "module": "esnext", - "target": "es2017", - "moduleResolution": "Node", - "lib": ["esnext", "ES2022", "ES2017"], - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "skipLibCheck": true, - "strict": false - }, - "include": [ - "**/*.ts", "./*.ts", - ] -} \ No newline at end of file