From d7759a06ad5101b5e649a75bfdffd88ce4353afa Mon Sep 17 00:00:00 2001 From: Vignesh Date: Thu, 11 Jul 2024 15:56:46 +0530 Subject: [PATCH 1/2] added offchain whitelisting --- admin_frontend/package-lock.json | 4 +- .../src/constants/defaultNetworks.json | 570 ++++++++-------- .../20240711000005-create-whitelist.cjs | 46 ++ backend/src/constants/ErrorMessage.ts | 4 + backend/src/models/api-key.ts | 10 +- backend/src/models/sponsorship-policy.ts | 1 + backend/src/models/whitelist.ts | 61 ++ backend/src/paymaster/index.ts | 8 +- backend/src/plugins/sequelizePlugin.ts | 9 +- .../sponsorship-policy-repository.ts | 3 +- .../src/repository/whitelist-repository.ts | 111 +++ backend/src/routes/paymaster-routes.ts | 18 +- .../src/routes/sponsorship-policy-routes.ts | 4 +- backend/src/routes/whitelist-routes.ts | 640 +++++++++++++----- backend/src/types/whitelist-dto.ts | 5 + 15 files changed, 1016 insertions(+), 478 deletions(-) create mode 100644 backend/migrations/20240711000005-create-whitelist.cjs create mode 100644 backend/src/models/whitelist.ts create mode 100644 backend/src/repository/whitelist-repository.ts create mode 100644 backend/src/types/whitelist-dto.ts diff --git a/admin_frontend/package-lock.json b/admin_frontend/package-lock.json index 8a4bf82..88014f3 100644 --- a/admin_frontend/package-lock.json +++ b/admin_frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "admin_frontend", - "version": "1.2.4", + "version": "1.2.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "admin_frontend", - "version": "1.2.4", + "version": "1.2.8", "dependencies": { "@emotion/react": "11.11.3", "@emotion/styled": "11.11.0", diff --git a/admin_frontend/src/constants/defaultNetworks.json b/admin_frontend/src/constants/defaultNetworks.json index 7c6d48a..f2ad24e 100644 --- a/admin_frontend/src/constants/defaultNetworks.json +++ b/admin_frontend/src/constants/defaultNetworks.json @@ -1,282 +1,292 @@ [ - { - "chainId": 1, - "bundler": "https://ethereum-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x7F690e93CecFca5A31E6e1dF50A33F6d3059048c" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 10, - "bundler": "https://optimism-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0x805650ce74561C85baA44a8Bd13E19633Fd0F79d" - }, - "thresholdValue": "21.8", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 14, - "bundler": "https://flare-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0x8A41594e5c6Fe492e437414c24eA6f401186b8d2" - }, - "thresholdValue": "1556", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 30, - "bundler": "https://rootstock-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26dD53b325bFFaACdFA224692EFF4C448C4" - }, - "thresholdValue": "0.00079", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 31, - "bundler": "https://testnet-rpc.etherspot.io/v1/31", - "contracts": { - "etherspotPaymasterAddress": "0xD302BE6e9D3fE0fBf8122a0C34611E31c0D0E792" - }, - "thresholdValue": "0.00079", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 56, - "bundler": "https://bnb-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0xEA5ecE95D3A28f9faB161779d20128b449F9EC9C" - }, - "thresholdValue": "0.09", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 97, - "bundler": "https://testnet-rpc.etherspot.io/v1/97", - "contracts": { - "etherspotPaymasterAddress": "0x153e26707DF3787183945B88121E4Eb188FDCAAA" - }, - "thresholdValue": "0.09", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 100, - "bundler": "https://gnosis-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x373aBcF1EA9e5802778E32870e7f72C8A6a90349" - }, - "thresholdValue": "50", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 114, - "bundler": "https://testnet-rpc.etherspot.io/v1/114", - "contracts": { - "etherspotPaymasterAddress": "0x2a18C360b525824B3e5656B5a705554f2a5036Be" - }, - "thresholdValue": "1556", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 122, - "bundler": "https://fuse-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0xEC2EE24E79C73DB13Dd9bC782856a5296626b7eb" - }, - "thresholdValue": "669", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 123, - "bundler": "https://testnet-rpc.etherspot.io/v1/123", - "contracts": { - "etherspotPaymasterAddress": "0xAF628C207513c5E51d894b3733056B8080634923" - }, - "thresholdValue": "669", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 137, - "bundler": "https://polygon-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0x26FeC24b0D467C9de105217B483931e8f944ff50" - }, - "thresholdValue": "69.85", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 5000, - "bundler": "https://mantle-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x8A41594e5c6Fe492e437414c24eA6f401186b8d2" - }, - "thresholdValue": "44.24", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 5003, - "bundler": "https://testnet-rpc.etherspot.io/v1/5003", - "contracts": { - "etherspotPaymasterAddress": "0x8350355c08aDAC387b443782124A30A8942BeC2e" - }, - "thresholdValue": "44.24", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 8217, - "bundler": "https://klaytn-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x4ebd86AAF89151b5303DB072e0205C668e31E5E7" - }, - "thresholdValue": "275.2", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 8453, - "bundler": "https://base-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" - }, - "thresholdValue": "15.19", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 42161, - "bundler": "https://arbitrum-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0xEC2EE24E79C73DB13Dd9bC782856a5296626b7eb" - }, - "thresholdValue": "43.10", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 43114, - "bundler": "https://avalanche-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0x527569794781671319f20374A050BDbef4181aB3" - }, - "thresholdValue": "1.4", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 59144, - "bundler": "https://linea-bundler.etherspot.io/", - "contracts": { - "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 84532, - "bundler": "https://testnet-rpc.etherspot.io/v1/84532", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" - }, - "thresholdValue": "15.19", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 421614, - "bundler": "https://testnet-rpc.etherspot.io/v1/421614", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" - }, - "thresholdValue": "43.10", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 534351, - "bundler": "https://testnet-rpc.etherspot.io/v1/534351", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 534352, - "bundler": "https://scroll-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 11155111, - "bundler": "https://testnet-rpc.etherspot.io/v1/11155111", - "contracts": { - "etherspotPaymasterAddress": "0xcaDBADcFeD5530A49762DFc9d1d712CcD6b09b25" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 28122024, - "bundler": "https://testnet-rpc.etherspot.io/v1/28122024", - "contracts": { - "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "orochi", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 11155420, - "bundler": "https://testnet-rpc.etherspot.io/v1/11155420", - "contracts": { - "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" - }, - "thresholdValue": "21.8", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 888888888, - "bundler": "https://ancient8-bundler.etherspot.io", - "contracts": { - "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" - }, - "thresholdValue": "0.016", - "MultiTokenPaymasterOracleUsed": "orochi", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - }, - { - "chainId": 80002, - "bundler": "https://testnet-rpc.etherspot.io/v1/80002", - "contracts": { - "etherspotPaymasterAddress": "0xe893a26dd53b325bffaacdfa224692eff4c448c4" - }, - "thresholdValue": "0.01", - "MultiTokenPaymasterOracleUsed": "chainlink", - "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" - } + { + "chainId": 1, + "bundler": "https://ethereum-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x7F690e93CecFca5A31E6e1dF50A33F6d3059048c" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 10, + "bundler": "https://optimism-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0x805650ce74561C85baA44a8Bd13E19633Fd0F79d" + }, + "thresholdValue": "21.8", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 14, + "bundler": "https://flare-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0x8A41594e5c6Fe492e437414c24eA6f401186b8d2" + }, + "thresholdValue": "1556", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 30, + "bundler": "https://rootstock-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26dD53b325bFFaACdFA224692EFF4C448C4" + }, + "thresholdValue": "0.00079", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 31, + "bundler": "https://testnet-rpc.etherspot.io/v1/31", + "contracts": { + "etherspotPaymasterAddress": "0xD302BE6e9D3fE0fBf8122a0C34611E31c0D0E792" + }, + "thresholdValue": "0.00079", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 56, + "bundler": "https://bnb-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0xEA5ecE95D3A28f9faB161779d20128b449F9EC9C" + }, + "thresholdValue": "0.09", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 97, + "bundler": "https://testnet-rpc.etherspot.io/v1/97", + "contracts": { + "etherspotPaymasterAddress": "0x153e26707DF3787183945B88121E4Eb188FDCAAA" + }, + "thresholdValue": "0.09", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 100, + "bundler": "https://gnosis-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x373aBcF1EA9e5802778E32870e7f72C8A6a90349" + }, + "thresholdValue": "50", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 114, + "bundler": "https://testnet-rpc.etherspot.io/v1/114", + "contracts": { + "etherspotPaymasterAddress": "0x2a18C360b525824B3e5656B5a705554f2a5036Be" + }, + "thresholdValue": "1556", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 122, + "bundler": "https://fuse-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0xEC2EE24E79C73DB13Dd9bC782856a5296626b7eb" + }, + "thresholdValue": "669", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 123, + "bundler": "https://testnet-rpc.etherspot.io/v1/123", + "contracts": { + "etherspotPaymasterAddress": "0xAF628C207513c5E51d894b3733056B8080634923" + }, + "thresholdValue": "669", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 137, + "bundler": "https://polygon-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0x26FeC24b0D467C9de105217B483931e8f944ff50" + }, + "thresholdValue": "69.85", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 5000, + "bundler": "https://mantle-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x8A41594e5c6Fe492e437414c24eA6f401186b8d2" + }, + "thresholdValue": "44.24", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 5003, + "bundler": "https://testnet-rpc.etherspot.io/v1/5003", + "contracts": { + "etherspotPaymasterAddress": "0x8350355c08aDAC387b443782124A30A8942BeC2e" + }, + "thresholdValue": "44.24", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 8217, + "bundler": "https://klaytn-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x4ebd86AAF89151b5303DB072e0205C668e31E5E7" + }, + "thresholdValue": "275.2", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 8453, + "bundler": "https://base-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" + }, + "thresholdValue": "15.19", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 42161, + "bundler": "https://arbitrum-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0xEC2EE24E79C73DB13Dd9bC782856a5296626b7eb" + }, + "thresholdValue": "43.10", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 43114, + "bundler": "https://avalanche-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0x527569794781671319f20374A050BDbef4181aB3" + }, + "thresholdValue": "1.4", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 59144, + "bundler": "https://linea-bundler.etherspot.io/", + "contracts": { + "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 84532, + "bundler": "https://testnet-rpc.etherspot.io/v1/84532", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" + }, + "thresholdValue": "15.19", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 421614, + "bundler": "https://testnet-rpc.etherspot.io/v1/421614", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" + }, + "thresholdValue": "43.10", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 534351, + "bundler": "https://testnet-rpc.etherspot.io/v1/534351", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 534352, + "bundler": "https://scroll-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 11155111, + "bundler": "https://testnet-rpc.etherspot.io/v1/11155111", + "contracts": { + "etherspotPaymasterAddress": "0xcaDBADcFeD5530A49762DFc9d1d712CcD6b09b25" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 28122024, + "bundler": "https://testnet-rpc.etherspot.io/v1/28122024", + "contracts": { + "etherspotPaymasterAddress": "0xe893A26DD53b325BffAacDfA224692EfF4C448c4" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "orochi", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 11155420, + "bundler": "https://testnet-rpc.etherspot.io/v1/11155420", + "contracts": { + "etherspotPaymasterAddress": "0xB3AD9B9B06c6016f81404ee8FcCD0526F018Cf0C" + }, + "thresholdValue": "21.8", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 888888888, + "bundler": "https://ancient8-bundler.etherspot.io", + "contracts": { + "etherspotPaymasterAddress": "0x810FA4C915015b703db0878CF2B9344bEB254a40" + }, + "thresholdValue": "0.016", + "MultiTokenPaymasterOracleUsed": "orochi", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 80002, + "bundler": "https://testnet-rpc.etherspot.io/v1/80002", + "contracts": { + "etherspotPaymasterAddress": "0xe893a26dd53b325bffaacdfa224692eff4c448c4" + }, + "thresholdValue": "0.01", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" + }, + { + "chainId": 80002, + "bundler": "https://testnet-rpc.etherspot.io/v2/80002", + "contracts": { + "etherspotPaymasterAddress": "0x9ddB9DC20E904206823184577e9C571c713d2c57" + }, + "thresholdValue": "0.01", + "MultiTokenPaymasterOracleUsed": "chainlink", + "entryPoint": "0x0000000071727De22E5E9d8BAf0edAc6f37da032" + } ] diff --git a/backend/migrations/20240711000005-create-whitelist.cjs b/backend/migrations/20240711000005-create-whitelist.cjs new file mode 100644 index 0000000..bec09a4 --- /dev/null +++ b/backend/migrations/20240711000005-create-whitelist.cjs @@ -0,0 +1,46 @@ +const { Sequelize, DataTypes } = require('sequelize') + +async function up({ context: queryInterface }) { + await queryInterface.createTable('arka_whitelist', { + "ID": { + type: Sequelize.INTEGER, + primaryKey: true, + autoIncrement: true, + allowNull: false + }, + "API_KEY": { + allowNull: false, + primaryKey: true, + type: Sequelize.TEXT + }, + "ADDRESSES": { + type: DataTypes.ARRAY(DataTypes.STRING), + allowNull: false, + }, + "POLICY_ID": { + type: Sequelize.INTEGER, + allowNull: true, + }, + "CREATED_AT": { + type: Sequelize.DATE, + allowNull: false, + defaultValue: Sequelize.NOW + }, + "UPDATED_AT": { + type: Sequelize.DATE, + allowNull: false, + defaultValue: Sequelize.NOW + } + }, { + schema: process.env.DATABASE_SCHEMA_NAME + }); +} + +async function down({ context: queryInterface }) { + await queryInterface.dropTable({ + tableName: 'arka_whitelist', + schema: process.env.DATABASE_SCHEMA_NAME + }); +} + +module.exports = { up, down } diff --git a/backend/src/constants/ErrorMessage.ts b/backend/src/constants/ErrorMessage.ts index ffdd79a..92f9c29 100644 --- a/backend/src/constants/ErrorMessage.ts +++ b/backend/src/constants/ErrorMessage.ts @@ -33,6 +33,10 @@ export default { API_KEY_VALIDATION_FAILED: 'Api Key is not in the right format as described in readme file', UNSUPPORTED_METHOD: 'Unsupported method name received', UNSUPPORTED_ENTRYPOINT: 'Unsupported EntryPoint Address', + ADDRESS_ALREADY_ADDED: 'Addresses were already added', + ADDRESS_NOT_WHITELISTED: 'Addresses sent were not whitelisted', + NO_WHITELIST_FOUND: 'No whitelist were found on the given apiKey/policyId', + INVALID_ADDRESS_PASSSED: 'Invalid Address passed', } export function generateErrorMessage(template: string, values: { [key: string]: string | number }): string { diff --git a/backend/src/models/api-key.ts b/backend/src/models/api-key.ts index e291f9d..3072d5c 100644 --- a/backend/src/models/api-key.ts +++ b/backend/src/models/api-key.ts @@ -32,27 +32,27 @@ export function initializeAPIKeyModel(sequelize: Sequelize, schema: string) { field: 'WALLET_ADDRESS' }, privateKey: { - type: DataTypes.STRING, + type: DataTypes.TEXT, allowNull: false, field: 'PRIVATE_KEY' }, supportedNetworks: { - type: DataTypes.STRING, + type: DataTypes.TEXT, allowNull: true, field: 'SUPPORTED_NETWORKS' }, erc20Paymasters: { - type: DataTypes.STRING, + type: DataTypes.TEXT, allowNull: true, field: 'ERC20_PAYMASTERS' }, multiTokenPaymasters: { - type: DataTypes.STRING, + type: DataTypes.TEXT, allowNull: true, field: 'MULTI_TOKEN_PAYMASTERS' }, multiTokenOracles: { - type: DataTypes.STRING, + type: DataTypes.TEXT, allowNull: true, field: 'MULTI_TOKEN_ORACLES' }, diff --git a/backend/src/models/sponsorship-policy.ts b/backend/src/models/sponsorship-policy.ts index 701bfa8..a58ae9c 100644 --- a/backend/src/models/sponsorship-policy.ts +++ b/backend/src/models/sponsorship-policy.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-inferrable-types */ import { Sequelize, DataTypes, Model } from 'sequelize'; export class SponsorshipPolicy extends Model { diff --git a/backend/src/models/whitelist.ts b/backend/src/models/whitelist.ts new file mode 100644 index 0000000..b26b097 --- /dev/null +++ b/backend/src/models/whitelist.ts @@ -0,0 +1,61 @@ +import { Sequelize, DataTypes, Model } from 'sequelize'; + +export class ArkaWhitelist extends Model { + public id!: number; // Note that the `null assertion` `!` is required in strict mode. + public apiKey!: string; + public addresses!: string[]; + public policyId?: number; + public readonly createdAt!: Date; + public readonly updatedAt!: Date; +} + +const initializeArkaWhitelistModel = (sequelize: Sequelize, schema: string) => { + ArkaWhitelist.init({ + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + allowNull: false, + field: 'ID' + }, + apiKey: { + type: DataTypes.TEXT, + allowNull: false, + primaryKey: true, + field: 'API_KEY' + }, + addresses: { + type: DataTypes.ARRAY(DataTypes.STRING), + allowNull: false, + field: 'ADDRESSES' + }, + policyId: { + type: DataTypes.INTEGER, + allowNull: true, + field: 'POLICY_ID' + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW, + field: 'CREATED_AT' + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW, + field: 'UPDATED_AT' + }, + }, { + sequelize, + tableName: 'arka_whitelist', + modelName: 'ArkaWhitelist', + timestamps: true, + createdAt: 'createdAt', + updatedAt: 'updatedAt', + freezeTableName: true, + schema: schema, + }); +}; + +export { initializeArkaWhitelistModel }; \ No newline at end of file diff --git a/backend/src/paymaster/index.ts b/backend/src/paymaster/index.ts index 244afee..5d5a15c 100644 --- a/backend/src/paymaster/index.ts +++ b/backend/src/paymaster/index.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { providers, Wallet, ethers, Contract, BigNumber, BigNumberish, utils } from 'ethers'; +import { providers, Wallet, ethers, Contract, BigNumber, BigNumberish } from 'ethers'; import { arrayify, BytesLike, defaultAbiCoder, hexConcat, hexZeroPad } from 'ethers/lib/utils.js'; import { FastifyBaseLogger } from 'fastify'; import EtherspotAbiV06 from '../abi/EtherspotAbi.js'; @@ -14,7 +14,7 @@ import ChainlinkOracleAbi from '../abi/ChainlinkOracleAbi.js'; export class Paymaster { feeMarkUp: BigNumber; - multiTokenMarkUp: Number; + multiTokenMarkUp: number; constructor(feeMarkUp: string, multiTokenMarkUp: string) { this.feeMarkUp = ethers.utils.parseUnits(feeMarkUp, 'gwei'); @@ -71,7 +71,7 @@ export class Paymaster { } const accountGasLimits = this.packUint(userOp.verificationGasLimit, userOp.callGasLimit) const gasFees = this.packUint(userOp.maxPriorityFeePerGas, userOp.maxFeePerGas); - let packedUserOp = { + const packedUserOp = { sender: userOp.sender, nonce: userOp.nonce, initCode: userOp.initCode, @@ -83,7 +83,7 @@ export class Paymaster { signature: userOp.signature } - let paymasterData = await this.getPaymasterData(packedUserOp, validUntil, validAfter, paymasterContract, signer); + const paymasterData = await this.getPaymasterData(packedUserOp, validUntil, validAfter, paymasterContract, signer); let returnValue; if (estimate) { returnValue = { diff --git a/backend/src/plugins/sequelizePlugin.ts b/backend/src/plugins/sequelizePlugin.ts index 27aed77..4f094b9 100644 --- a/backend/src/plugins/sequelizePlugin.ts +++ b/backend/src/plugins/sequelizePlugin.ts @@ -8,6 +8,8 @@ import { initializeArkaConfigModel } from "../models/arka-config.js"; import { APIKeyRepository } from "../repository/api-key-repository.js"; import { ArkaConfigRepository } from "../repository/arka-config-repository.js"; import { SponsorshipPolicyRepository } from "../repository/sponsorship-policy-repository.js"; +import { WhitelistRepository } from "../repository/whitelist-repository.js"; +import { initializeArkaWhitelistModel } from "../models/whitelist.js"; const pg = await import('pg'); const Client = pg.default.Client; @@ -46,10 +48,10 @@ const sequelizePlugin: FastifyPluginAsync = async (server) => { // Initialize models initializeArkaConfigModel(sequelize, server.config.DATABASE_SCHEMA_NAME); - const initializedAPIKeyModel = initializeAPIKeyModel(sequelize, server.config.DATABASE_SCHEMA_NAME); - //sequelize.models.APIKey = initializedAPIKeyModel; + initializeAPIKeyModel(sequelize, server.config.DATABASE_SCHEMA_NAME); server.log.info(`Initialized APIKey model... ${sequelize.models.APIKey}`); initializeSponsorshipPolicyModel(sequelize, server.config.DATABASE_SCHEMA_NAME); + initializeArkaWhitelistModel(sequelize, server.config.DATABASE_SCHEMA_NAME); server.log.info('Initialized SponsorshipPolicy model...'); server.log.info('Initialized all models...'); @@ -62,6 +64,8 @@ const sequelizePlugin: FastifyPluginAsync = async (server) => { server.decorate('arkaConfigRepository', arkaConfigRepository); const sponsorshipPolicyRepository = new SponsorshipPolicyRepository(sequelize); server.decorate('sponsorshipPolicyRepository', sponsorshipPolicyRepository); + const whitelistRepository: WhitelistRepository = new WhitelistRepository(sequelize); + server.decorate('whitelistRepository', whitelistRepository); server.log.info('decorated fastify server with models...'); @@ -78,6 +82,7 @@ declare module "fastify" { apiKeyRepository: APIKeyRepository; arkaConfigRepository: ArkaConfigRepository; sponsorshipPolicyRepository: SponsorshipPolicyRepository; + whitelistRepository: WhitelistRepository; } } diff --git a/backend/src/repository/sponsorship-policy-repository.ts b/backend/src/repository/sponsorship-policy-repository.ts index 30d46e7..10159b0 100644 --- a/backend/src/repository/sponsorship-policy-repository.ts +++ b/backend/src/repository/sponsorship-policy-repository.ts @@ -2,7 +2,6 @@ import { Sequelize, Op } from 'sequelize'; import { SponsorshipPolicy } from '../models/sponsorship-policy.js'; import { EPVersions, SponsorshipPolicyDto, getEPVersionString } from '../types/sponsorship-policy-dto.js'; import { ethers } from 'ethers'; -import { server } from 'server.js'; export class SponsorshipPolicyRepository { private sequelize: Sequelize; @@ -545,7 +544,7 @@ export class SponsorshipPolicyRepository { } validateSponsorshipPolicy(sponsorshipPolicy: SponsorshipPolicyDto) { - let errors: string[] = []; + const errors: string[] = []; if (!sponsorshipPolicy.name || !sponsorshipPolicy.description) { errors.push('Name and description are required fields'); diff --git a/backend/src/repository/whitelist-repository.ts b/backend/src/repository/whitelist-repository.ts new file mode 100644 index 0000000..fa86c90 --- /dev/null +++ b/backend/src/repository/whitelist-repository.ts @@ -0,0 +1,111 @@ +import { Sequelize } from 'sequelize'; +import { WhitelistDto } from '../types/whitelist-dto.js'; +import { ArkaWhitelist } from '../models/whitelist.js'; + +export class WhitelistRepository { + private sequelize: Sequelize; + + constructor(sequelize: Sequelize) { + this.sequelize = sequelize; + } + + async create(apiKey: WhitelistDto): Promise { + // generate APIKey sequelize model instance from APIKeyDto + const result = await this.sequelize.models.ArkaWhitelist.create({ + apiKey: apiKey.apiKey, + addresses: apiKey.addresses, + policyId: apiKey.policyId ?? null, + }) as ArkaWhitelist; + + + + return result; + } + + async delete(apiKey: string): Promise { + const deletedCount = await this.sequelize.models.ArkaWhitelist.destroy({ + where + : { apiKey: apiKey } + }); + + if (deletedCount === 0) { + throw new Error('APIKey deletion failed'); + } + + return deletedCount; + } + + async findAll(): Promise { + const result = await this.sequelize.models.APIKey.findAll(); + return result.map(apiKey => apiKey.get() as ArkaWhitelist); + } + + async findOneByApiKeyAndPolicyId(apiKey: string, policyId?: number): Promise { + let result; + if (policyId) { + result = await this.sequelize.models.ArkaWhitelist.findOne({ where: { apiKey: apiKey, policyId: policyId } }); + } else { + result = await this.sequelize.models.ArkaWhitelist.findOne({ where: { apiKey: apiKey, policyId: null } }); + } + return result ? result.get() as ArkaWhitelist : null; + } + + async updateOneById(record: ArkaWhitelist): Promise { + const result = await this.sequelize.models.ArkaWhitelist.update({ + apiKey: record.apiKey, + addresses: record.addresses, + policyId: record.policyId + }, { + where: { id: record.id } + }) + + if (result[0] === 0) { + throw new Error(`ArkaWhitelist update failed for id: ${record.id}`); + } + + // return the updated record - fetch fresh from database + const updatedWhitelist = await this.findOneByApiKeyAndPolicyId(record.apiKey, record.policyId); + return updatedWhitelist as ArkaWhitelist; + } + + async deleteById(id: number): Promise { + + const deletedCount = await this.sequelize.models.ArkaWhitelist.destroy({ + where + : { id: id } + }); + + return deletedCount; + } + + async deleteAllBySponsorshipPolicies(id: number): Promise { + + const deletedCount = await this.sequelize.models.ArkaWhitelist.destroy({ + where + : { policyId: id } + }); + + return deletedCount; + } + + async deleteAllByApiKey(apiKey: string): Promise { + + const deletedCount = await this.sequelize.models.ArkaWhitelist.destroy({ + where + : { apiKey: apiKey } + }); + + return deletedCount; + } + + async deleteAllWhitelist(): Promise<{ message: string }> { + try { + await this.sequelize.models.ArkaWhitelist.destroy({ where: {} }); + return { message: 'Successfully deleted all whitelist' }; + } catch (err) { + console.error(err); + throw new Error('Failed to delete all whitelist'); + } + } + +} \ No newline at end of file diff --git a/backend/src/routes/paymaster-routes.ts b/backend/src/routes/paymaster-routes.ts index 5c29e63..5667ffc 100644 --- a/backend/src/routes/paymaster-routes.ts +++ b/backend/src/routes/paymaster-routes.ts @@ -54,16 +54,17 @@ const paymasterRoutes: FastifyPluginAsync = async (server) => { estimate = false; sponsorDetails = true; } + // eslint-disable-next-line no-fallthrough 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 }); } @@ -199,7 +200,7 @@ const paymasterRoutes: FastifyPluginAsync = async (server) => { if (!apiKeyData) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }); // get sponsorshipPolicy for the user from walletAddress and entrypoint version - const sponsorshipPolicy: SponsorshipPolicy | null = await server.sponsorshipPolicyRepository.findOneByWalletAddressAndSupportedEPVersion(apiKeyData?.walletAddress, getEPVersion(epVersion), chainId.chainId); + const sponsorshipPolicy: SponsorshipPolicy | null = await server.sponsorshipPolicyRepository.findOneByWalletAddressAndSupportedEPVersion(apiKeyData?.walletAddress, getEPVersion(epVersion)); if (!sponsorshipPolicy) { const errorMessage: string = generateErrorMessage(ErrorMessage.ACTIVE_SPONSORSHIP_POLICY_NOT_FOUND, { walletAddress: apiKeyData?.walletAddress, epVersion: epVersion, chainId: chainId.chainId }); return reply.code(ReturnCode.FAILURE).send({ error: errorMessage }); @@ -208,7 +209,7 @@ const paymasterRoutes: FastifyPluginAsync = async (server) => { if (!Object.assign(new SponsorshipPolicy(), sponsorshipPolicy).isApplicable) { const errorMessage: string = generateErrorMessage(ErrorMessage.NO_ACTIVE_SPONSORSHIP_POLICY_FOR_CURRENT_TIME, { walletAddress: apiKeyData?.walletAddress, epVersion: epVersion, chainId: chainId.chainId }); return reply.code(ReturnCode.FAILURE).send({ error: errorMessage }); - } + } // get supported networks from sponsorshipPolicy const supportedNetworks: number[] | undefined | null = sponsorshipPolicy.enabledChains; @@ -238,7 +239,14 @@ const paymasterRoutes: FastifyPluginAsync = async (server) => { 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); + else { + const globalWhitelistRecord = await server.whitelistRepository.findOneByApiKeyAndPolicyId(api_key); + if (!globalWhitelistRecord?.addresses.includes(userOp.sender)) { + const existingWhitelistRecord = await server.whitelistRepository.findOneByApiKeyAndPolicyId(api_key, sponsorshipPolicy.id); + if (!existingWhitelistRecord?.addresses.includes(userOp.sender)) throw new Error('This sender address has not been whitelisted yet'); + } + result = await paymaster.signV07(userOp, str, str1, entryPoint, networkConfig.contracts.etherspotPaymasterAddress, networkConfig.bundler, signer, estimate, server.log); + } break; } case 'erc20': { diff --git a/backend/src/routes/sponsorship-policy-routes.ts b/backend/src/routes/sponsorship-policy-routes.ts index 0c172e4..fff733e 100644 --- a/backend/src/routes/sponsorship-policy-routes.ts +++ b/backend/src/routes/sponsorship-policy-routes.ts @@ -326,7 +326,9 @@ const sponsorshipPolicyRoutes: FastifyPluginAsync = async (server) => { validateRequestHeader(request, reply, server, apiKey.walletAddress); - const result = await server.sponsorshipPolicyRepository.deleteSponsorshipPolicy(id); + await server.whitelistRepository.deleteAllBySponsorshipPolicies(id); + + await server.sponsorshipPolicyRepository.deleteSponsorshipPolicy(id); return reply.code(200).send({ message: `Successfully deleted policy with id ${id}` }); } catch (err) { request.log.error(err); diff --git a/backend/src/routes/whitelist-routes.ts b/backend/src/routes/whitelist-routes.ts index 924dd27..beaf42d 100644 --- a/backend/src/routes/whitelist-routes.ts +++ b/backend/src/routes/whitelist-routes.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { FastifyPluginAsync } from "fastify"; -import { ethers } from "ethers"; +import { ethers, Wallet } from "ethers"; import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager"; import { Paymaster } from "../paymaster/index.js"; import SupportedNetworks from "../../config.json" assert { type: "json" }; @@ -11,194 +11,480 @@ import { printRequest, getNetworkConfig } from "../utils/common.js"; import { APIKey } from "../models/api-key.js"; const SUPPORTED_ENTRYPOINTS = { - 'EPV_06': "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", - 'EPV_07': "0x0000000071727De22E5E9d8BAf0edAc6f37da032" + 'EPV_06': "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + 'EPV_07': "0x0000000071727De22E5E9d8BAf0edAc6f37da032" } const whitelistRoutes: 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; + let client: SecretsManagerClient; - const unsafeMode: boolean = process.env.UNSAFE_MODE == "true" ? true : false; + const unsafeMode: boolean = process.env.UNSAFE_MODE == "true" ? true : false; - if (!unsafeMode) { - client = new SecretsManagerClient(); + if (!unsafeMode) { + client = new SecretsManagerClient(); + } + + 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 apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); + if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) + privateKey = decode(apiKeyEntity.privateKey, server.config.HMAC_SECRET); + supportedNetworks = apiKeyEntity.supportedNetworks; + } + 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: ErrorMessage.INVALID_ADDRESS_PASSSED }); + 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 apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); - if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - privateKey = decode(apiKeyEntity.privateKey, server.config.HMAC_SECRET); - supportedNetworks = apiKeyEntity.supportedNetworks; - } - 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 apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); + if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) + privateKey = decode(apiKeyEntity.privateKey, server.config.HMAC_SECRET); + supportedNetworks = apiKeyEntity.supportedNetworks; + } + 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: ErrorMessage.INVALID_ADDRESS_PASSSED }); + 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 }) + } + }) + + 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 apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); + if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) + privateKey = decode(apiKeyEntity.privateKey, server.config.HMAC_SECRET); + supportedNetworks = apiKeyEntity.supportedNetworks; } - ) - - 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 apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); - if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - privateKey = decode(apiKeyEntity.privateKey, server.config.HMAC_SECRET); - supportedNetworks = apiKeyEntity.supportedNetworks; - } - 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 }) - } - }) - - 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 apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); - if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) - privateKey = decode(apiKeyEntity.privateKey, server.config.HMAC_SECRET); - supportedNetworks = apiKeyEntity.supportedNetworks; - } - 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 }) + 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("/removeWhitelist/v2", + async function (request, reply) { + try { + printRequest("/removeWhitelist/v2", request, server.log); + const body: any = request.body; + const query: any = request.query; + const address = body.params[0]; + const policyId = body.params[1]; + 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 }) + 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 apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); + if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) + privateKey = decode(apiKeyEntity.privateKey, server.config.HMAC_SECRET); + supportedNetworks = apiKeyEntity.supportedNetworks; + } + 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_07); + 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: ErrorMessage.INVALID_ADDRESS_PASSSED }); + const existingWhitelistRecord = await server.whitelistRepository.findOneByApiKeyAndPolicyId(api_key, policyId); + + + if (existingWhitelistRecord) { + const toBeRemoved: string[] = []; + address.filter(ele => { + if (existingWhitelistRecord.addresses.includes(ele)) { + toBeRemoved.push(ele); + existingWhitelistRecord.addresses.splice(existingWhitelistRecord.addresses.indexOf(ele), 1); } + }); + if (toBeRemoved.length < 1) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.ADDRESS_ALREADY_ADDED }); + + if (existingWhitelistRecord.addresses.length < 1) await server.whitelistRepository.deleteById(existingWhitelistRecord.id); + else await server.whitelistRepository.updateOneById(existingWhitelistRecord); + } else { + throw new Error(ErrorMessage.NO_WHITELIST_FOUND); + } + const result = { message: "Successfully deleted from Whitelist" } + 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("/checkWhitelist/v2", + async function (request, reply) { + try { + printRequest("/checkWhitelist/v2", request, server.log); + const body: any = request.body; + const query: any = request.query; + const accountAddress = body.params[0]; + const policyId = body.params[1]; + 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 }) + 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 apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); + if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) + privateKey = decode(apiKeyEntity.privateKey, server.config.HMAC_SECRET); + supportedNetworks = apiKeyEntity.supportedNetworks; + } + 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_07); + if (!networkConfig) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + const existingWhitelistRecord = await server.whitelistRepository.findOneByApiKeyAndPolicyId(api_key, policyId); + + if (!existingWhitelistRecord) { + throw new Error(ErrorMessage.NO_WHITELIST_FOUND); + } + const result = { message: existingWhitelistRecord.addresses.includes(accountAddress) ? 'Already added' : 'Not added yet' } + 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/v2", + async function (request, reply) { + try { + printRequest("/whitelist/v2", request, server.log); + const body: any = request.body; + const query: any = request.query; + const address = body.params[0]; + const policyId = body.params[1]; + 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 }) + 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 apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); + if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) + privateKey = decode(apiKeyEntity.privateKey, server.config.HMAC_SECRET); + supportedNetworks = apiKeyEntity.supportedNetworks; + } + 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_07); + 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: ErrorMessage.INVALID_ADDRESS_PASSSED }); + const signer = new Wallet(privateKey) + if (policyId) { + const policyRecord = await server.sponsorshipPolicyRepository.findOneById(policyId); + if (!policyRecord || (policyRecord?.walletAddress !== signer.address)) return reply.code(ReturnCode.FAILURE).send({error: ErrorMessage.INVALID_SPONSORSHIP_POLICY_ID }) } - ) + const existingWhitelistRecord = await server.whitelistRepository.findOneByApiKeyAndPolicyId(api_key, policyId); + + if (existingWhitelistRecord) { + const toBeAdded: string[] = []; + address.filter(ele => { + if (!existingWhitelistRecord.addresses.includes(ele)) toBeAdded.push(ele); + }); + if (toBeAdded.length < 1) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.ADDRESS_ALREADY_ADDED }); + const allAddresses = toBeAdded.concat(existingWhitelistRecord.addresses); + existingWhitelistRecord.addresses = allAddresses; + await server.whitelistRepository.updateOneById(existingWhitelistRecord); + } else { + const addWhitelistDto = { + apiKey: api_key, + addresses: address, + policyId: policyId ?? null, + } + await server.whitelistRepository.create(addWhitelistDto); + + } + const result = { message: "Successfully added to Whitelist" } + 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("/getAllWhitelist/v2", + async function (request, reply) { + try { + printRequest("/getAllWhitelist/v2", request, server.log); + const body: any = request.body; + const query: any = request.query; + const policyId = 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 apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); + if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) + privateKey = decode(apiKeyEntity.privateKey, server.config.HMAC_SECRET); + supportedNetworks = apiKeyEntity.supportedNetworks; + } + if (!privateKey) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) + if ( + !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_07); + if (!networkConfig) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.UNSUPPORTED_NETWORK }); + const existingWhitelistRecord = await server.whitelistRepository.findOneByApiKeyAndPolicyId(api_key, policyId); + + if (!existingWhitelistRecord) { + throw new Error(ErrorMessage.NO_WHITELIST_FOUND); + } + const result = { addresses: existingWhitelistRecord.addresses } + 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 }) + } + } + ) }; export default whitelistRoutes; diff --git a/backend/src/types/whitelist-dto.ts b/backend/src/types/whitelist-dto.ts new file mode 100644 index 0000000..e3bbc02 --- /dev/null +++ b/backend/src/types/whitelist-dto.ts @@ -0,0 +1,5 @@ +export interface WhitelistDto { + apiKey: string; + addresses: string[]; + policyId?: number; +} \ No newline at end of file From 09b332b78281d7306b78d86723e6d676f6227127 Mon Sep 17 00:00:00 2001 From: Vignesh Date: Fri, 12 Jul 2024 01:43:41 +0530 Subject: [PATCH 2/2] bumped up package version --- admin_frontend/package-lock.json | 4 ++-- admin_frontend/package.json | 2 +- backend/package.json | 2 +- frontend/package-lock.json | 4 ++-- frontend/package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/admin_frontend/package-lock.json b/admin_frontend/package-lock.json index 88014f3..9e3e514 100644 --- a/admin_frontend/package-lock.json +++ b/admin_frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "admin_frontend", - "version": "1.2.8", + "version": "1.2.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "admin_frontend", - "version": "1.2.8", + "version": "1.2.9", "dependencies": { "@emotion/react": "11.11.3", "@emotion/styled": "11.11.0", diff --git a/admin_frontend/package.json b/admin_frontend/package.json index db46c6d..a87ffa3 100644 --- a/admin_frontend/package.json +++ b/admin_frontend/package.json @@ -1,6 +1,6 @@ { "name": "admin_frontend", - "version": "1.2.8", + "version": "1.2.9", "private": true, "dependencies": { "@emotion/react": "11.11.3", diff --git a/backend/package.json b/backend/package.json index 09a8a7e..b7e6c1d 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "arka", - "version": "1.2.8", + "version": "1.2.9", "description": "ARKA - (Albanian for Cashier's case) is the first open source Paymaster as a service software", "type": "module", "directories": { diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7460a20..4397593 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "arka_frontend", - "version": "1.2.4", + "version": "1.2.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "arka_frontend", - "version": "1.2.4", + "version": "1.2.9", "dependencies": { "@babel/plugin-proposal-private-property-in-object": "7.21.11", "@emotion/react": "^11.11.1", diff --git a/frontend/package.json b/frontend/package.json index 21724ac..a91bd06 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "arka_frontend", - "version": "1.2.8", + "version": "1.2.9", "private": true, "dependencies": { "@babel/plugin-proposal-private-property-in-object": "7.21.11",