diff --git a/backend/CHANGELOG.md b/backend/CHANGELOG.md index df1b7b4..32e999d 100644 --- a/backend/CHANGELOG.md +++ b/backend/CHANGELOG.md @@ -1,4 +1,8 @@ # Changelog +## [4.2.2] - 2025-12-09 +- Default all the apiKey which would be saved hereafter and update the supportedNetworks to null to make the system only use config.json as default +- skips the getDeposit call from cronJob if the network is testnet + ## [4.2.0] - 2025-09-19 - Removed unused code in the repository - Removed the mode 'erc20' on paymaster routes since it used pimlico paymaster(v1) diff --git a/backend/migrations/20251209000001-update-supported-network-to-null.cjs b/backend/migrations/20251209000001-update-supported-network-to-null.cjs new file mode 100644 index 0000000..7cf612e --- /dev/null +++ b/backend/migrations/20251209000001-update-supported-network-to-null.cjs @@ -0,0 +1,9 @@ +require('dotenv').config(); + +async function up({ context: queryInterface }) { + await queryInterface.sequelize.query( + `UPDATE ${process.env.DATABASE_SCHEMA_NAME}."api_keys" SET "SUPPORTED_NETWORKS" = NULL` + ); +} + +module.exports = { up }; diff --git a/backend/package.json b/backend/package.json index 7e26a47..aee5140 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "arka", - "version": "4.2.1", + "version": "4.2.2", "description": "ARKA - (Albanian for Cashier's case) is the first open source Paymaster as a service software", "type": "module", "directories": { diff --git a/backend/src/paymaster/index.ts b/backend/src/paymaster/index.ts index df206ab..cd06675 100644 --- a/backend/src/paymaster/index.ts +++ b/backend/src/paymaster/index.ts @@ -1,17 +1,16 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { - createPublicClient, - createWalletClient, - http, - parseEther, - parseUnits, - formatUnits, - getAddress, - keccak256, - toHex, - concat, - hexToBytes, - bytesToHex, +import { + createPublicClient, + createWalletClient, + http, + parseEther, + parseUnits, + formatUnits, + getAddress, + keccak256, + toHex, + concat, + hexToBytes, encodeAbiParameters, Address, Hex, @@ -53,7 +52,7 @@ const nativePriceCacheTtl = parseInt(process.env.NATIVE_PRICE_CACHE_TTL || "6000 interface TokenPriceAndMetadata { decimals: number; symbol: string; - ethPrice: any; + ethPrice: string; gasToken: string } @@ -62,7 +61,7 @@ interface TokenPriceAndMetadataCache { expiry: number } -interface NativeCurrencyPricyCache { +interface NativeCurrencyPriceCache { data: any; expiry: number; } @@ -97,7 +96,7 @@ export class Paymaster { MTP_PVGL: string; MTP_PPGL: string; priceAndMetadata: Map = new Map(); - nativeCurrencyPrice: Map = new Map(); + nativeCurrencyPrice: Map = new Map(); coingeckoPrice: Map = new Map(); coingeckoService: CoingeckoService = new CoingeckoService(); sequelize: Sequelize; @@ -680,7 +679,7 @@ export class Paymaster { const priceAndMetadata: TokenPriceAndMetadata = { decimals: Number(data[0].value), symbol: data[1].value as any, - ethPrice: data[2].value, + ethPrice: data[2].value as string, gasToken } this.priceAndMetadata.set(cacheKey, { data: priceAndMetadata, expiry: Date.now() + ttl }); @@ -920,7 +919,7 @@ export class Paymaster { } else { const ecContract = getContract({ address: oracleAggregator as Address, abi: EtherspotChainlinkOracleAbi, client: publicClient }); const ETHprice = await ecContract.read.cachedPrice(); - ethPrice = ETHprice + ethPrice = ETHprice as string; } if (userOp.factory && userOp.factoryData) userOp.initCode = concat([userOp.factory as Hex, userOp.factoryData ?? '0x']) if (!userOp.signature) userOp.signature = '0x'; diff --git a/backend/src/plugins/sequelizePlugin.ts b/backend/src/plugins/sequelizePlugin.ts index 4579cec..919dbe7 100644 --- a/backend/src/plugins/sequelizePlugin.ts +++ b/backend/src/plugins/sequelizePlugin.ts @@ -100,6 +100,7 @@ declare module "fastify" { sponsorshipPolicyRepository: SponsorshipPolicyRepository; whitelistRepository: WhitelistRepository; contractWhitelistRepository: ContractWhitelistRepository; + coingeckoRepo: CoingeckoTokensRepository; multiTokenPaymasterRepository: MultiTokenPaymasterRepository; } } diff --git a/backend/src/routes/admin-routes.ts b/backend/src/routes/admin-routes.ts index ab4a8b9..4f8bc83 100644 --- a/backend/src/routes/admin-routes.ts +++ b/backend/src/routes/admin-routes.ts @@ -170,7 +170,7 @@ const adminRoutes: FastifyPluginAsync = async (server) => { apiKey: body.apiKey, walletAddress: publicAddress, privateKey: encode(privateKey, server.config.HMAC_SECRET), - supportedNetworks: body.supportedNetworks, + supportedNetworks: null, // By Default all networks given in config.json will be supported erc20Paymasters: body.erc20Paymasters, multiTokenPaymasters: body.multiTokenPaymasters ?? null, multiTokenOracles: body.multiTokenOracles ?? null, @@ -192,7 +192,7 @@ const adminRoutes: FastifyPluginAsync = async (server) => { apiKey: body.apiKey, walletAddress: publicAddress, privateKey: encode(privateKey, server.config.HMAC_SECRET), - supportedNetworks: body.supportedNetworks, + supportedNetworks: null, // By Default all networks given in config.json will be supported erc20Paymasters: body.erc20Paymasters, multiTokenPaymasters: body.multiTokenPaymasters ?? null, multiTokenOracles: body.multiTokenOracles ?? null, @@ -229,7 +229,7 @@ const adminRoutes: FastifyPluginAsync = async (server) => { return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.RECORD_NOT_FOUND }); await apiKeyInstance.update({ - supportedNetworks: body.supportedNetworks, + supportedNetworks: null, // By Default all networks given in config.json will be supported erc20Paymasters: body.erc20Paymasters, transactionLimit: body.transactionLimit ?? 0, noOfTransactionsInAMonth: body.noOfTransactionsInAMonth ?? 10, diff --git a/backend/src/routes/sponsorship-policy-routes.ts b/backend/src/routes/sponsorship-policy-routes.ts index 97a5817..c25dcfc 100644 --- a/backend/src/routes/sponsorship-policy-routes.ts +++ b/backend/src/routes/sponsorship-policy-routes.ts @@ -149,7 +149,7 @@ const sponsorshipPolicyRoutes: FastifyPluginAsync = async (server) => { return reply.code(ReturnCode.BAD_REQUEST).send({ error: ErrorMessage.INVALID_DATA }); } - const result = await server.sponsorshipPolicyRepository.findOneByWalletAddressAndChain(walletAddress, chainId); + const result = await server.sponsorshipPolicyRepository.findOneByWalletAddressAndChain(walletAddress, Number(chainId)); if (!result) { return reply.code(ReturnCode.NOT_FOUND).send({ error: ErrorMessage.SPONSORSHIP_POLICY_NOT_FOUND }); } diff --git a/backend/src/server.ts b/backend/src/server.ts index e7fc630..c410b2a 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -40,7 +40,7 @@ import { MultiTokenPaymaster } from './models/multiTokenPaymaster.js'; import { MULTI_TOKEN_ORACLES, MULTI_TOKEN_PAYMASTERS } from './constants/MultiTokenPaymasterCronJob.js'; let server: FastifyInstance; -const defaultThrustholdValue = '0.001'; // in ETH +const defaultThresholdValue = '0.001'; // in ETH const defaultTokenOracleDecimals = 8; // Standard oracle decimal const initializeServer = async (): Promise => { @@ -314,7 +314,7 @@ const initializeServer = async (): Promise => { const thresholdValue = network.thresholdValue ?? networkConfig.thresholdValue; const bundler = network.bundler ?? networkConfig.bundler; if (network.contracts?.etherspotPaymasterAddress) { - checkDeposit(network.contracts.etherspotPaymasterAddress, bundler, process.env.WEBHOOK_URL, thresholdValue ?? defaultThrustholdValue, Number(network.chainId), server.log); + checkDeposit(network.contracts.etherspotPaymasterAddress, bundler, process.env.WEBHOOK_URL, thresholdValue ?? defaultThresholdValue, Number(network.chainId), server.log); } } } @@ -335,7 +335,7 @@ const initializeServer = async (): Promise => { if (networkConfig) { const bundler = networkConfig.bundler; for (const symbol in customPaymasters[chainId]) { - checkDeposit(customPaymasters[chainId][symbol], bundler, process.env.WEBHOOK_URL, networkConfig.thresholdValue ?? defaultThrustholdValue, Number(chainId), server.log) + checkDeposit(customPaymasters[chainId][symbol], bundler, process.env.WEBHOOK_URL, networkConfig.thresholdValue ?? defaultThresholdValue, Number(chainId), server.log) } } } @@ -349,7 +349,7 @@ const initializeServer = async (): Promise => { if (networkConfig) { const bundler = networkConfig.bundler; for (const symbol in customPaymastersV2[chainId]) { - checkDeposit(customPaymastersV2[chainId][symbol], bundler, process.env.WEBHOOK_URL, networkConfig.thresholdValue ?? defaultThrustholdValue, Number(chainId), server.log); + checkDeposit(customPaymastersV2[chainId][symbol], bundler, process.env.WEBHOOK_URL, networkConfig.thresholdValue ?? defaultThresholdValue, Number(chainId), server.log); } } } @@ -359,7 +359,7 @@ const initializeServer = async (): Promise => { // checking deposit for epv6 native paymasters from default config.json. for (const network of SupportedNetworks) { if (network.contracts?.etherspotPaymasterAddress) { - checkDeposit(network.contracts.etherspotPaymasterAddress, network.bundler, process.env.WEBHOOK_URL, network.thresholdValue ?? defaultThrustholdValue, Number(network.chainId), server.log); + checkDeposit(network.contracts.etherspotPaymasterAddress, network.bundler, process.env.WEBHOOK_URL, network.thresholdValue ?? defaultThresholdValue, Number(network.chainId), server.log); } } @@ -368,7 +368,7 @@ const initializeServer = async (): Promise => { result.forEach((record: MultiTokenPaymaster) => { const networkConfig = getNetworkConfig(record.chainId, '', server.config.EPV_06); if (networkConfig) - checkDeposit(getAddress(record.paymasterAddress), networkConfig.bundler, process.env.WEBHOOK_URL ?? '', networkConfig.thresholdValue ?? defaultThrustholdValue, record.chainId, server.log); + checkDeposit(getAddress(record.paymasterAddress), networkConfig.bundler, process.env.WEBHOOK_URL ?? '', networkConfig.thresholdValue ?? defaultThresholdValue, record.chainId, server.log); }) } } catch (err) { diff --git a/backend/src/utils/common.ts b/backend/src/utils/common.ts index f343da5..a99879b 100644 --- a/backend/src/utils/common.ts +++ b/backend/src/utils/common.ts @@ -2,10 +2,10 @@ import { FastifyBaseLogger, FastifyRequest } from "fastify"; import { createPublicClient, defineChain, http, parseUnits } from "viem"; import SupportedNetworks from "../../config.json"; -import { EtherscanResponse, getEtherscanFeeResponse } from "./interface.js"; +import { EtherscanResponse, getEtherscanFeeResponse, NetworkConfig } from "./interface.js"; import * as chains from 'viem/chains' -export function printRequest(methodName: string, request: FastifyRequest, log: FastifyBaseLogger) { +export function printRequest(methodName: string, request: FastifyRequest, log: FastifyBaseLogger): void { log.info(methodName, "called: "); log.info(request.query, "query passed: "); log.info(request.body, "body passed: "); @@ -33,20 +33,20 @@ export function getViemChainDef(chainId: number, rpcUrl?: string): chains.Chain return customChain; } -export function getNetworkConfig(key: any, supportedNetworks: any, entryPoint?: string[]) { +export function getNetworkConfig(key: any, supportedNetworks: any, entryPoint?: string[]): NetworkConfig | null { if (supportedNetworks !== '') { const buffer = Buffer.from(supportedNetworks, 'base64'); const SUPPORTED_NETWORKS = JSON.parse(buffer.toString()); if (entryPoint === undefined || entryPoint === null || entryPoint.length === 0) { const result = SUPPORTED_NETWORKS.find((chain: any) => chain["chainId"] == key); if (!result) { - return SupportedNetworks.find((chain) => chain.chainId == key); + return SupportedNetworks.find((chain) => chain.chainId == key) || null; } return result; } const result = SUPPORTED_NETWORKS.find((chain: any) => { return chain["chainId"] == key && entryPoint.includes(chain["entryPoint"]) }); if (!result) { - return SupportedNetworks.find((chain) => chain.chainId == key && entryPoint.includes(chain.entryPoint)); + return SupportedNetworks.find((chain) => chain.chainId == key && entryPoint.includes(chain.entryPoint)) || null; } return result } else { @@ -62,16 +62,16 @@ export function getNetworkConfig(key: any, supportedNetworks: any, entryPoint?: } } -export function getChainIdsFromDefaultSupportedNetworks() { +export function getChainIdsFromDefaultSupportedNetworks(): number[] { return SupportedNetworks.map((chain) => chain.chainId); } -export function decodeSupportedNetworks(supportedNetworksForDecode: string) { +export function decodeSupportedNetworks(supportedNetworksForDecode: string): NetworkConfig[] { const buffer = Buffer.from(supportedNetworksForDecode, "base64"); return JSON.parse(buffer.toString()); } -export function getChainIdsFromSupportedNetworks(supportedNetworksForDecode: string) { +export function getChainIdsFromSupportedNetworks(supportedNetworksForDecode: string): number[] { const decodedSupportedNetworks = decodeSupportedNetworks(supportedNetworksForDecode); if(!decodedSupportedNetworks) return []; diff --git a/backend/src/utils/interface.ts b/backend/src/utils/interface.ts index d19c54f..4ba6ab9 100644 --- a/backend/src/utils/interface.ts +++ b/backend/src/utils/interface.ts @@ -17,4 +17,15 @@ export interface getEtherscanFeeResponse { maxFeePerGas: bigint; maxPriorityFeePerGas: bigint; gasPrice: bigint; +} + +export interface NetworkConfig { + chainId: number; + bundler: string; + contracts: { + etherspotPaymasterAddress: string; + }; + thresholdValue: string; + MultiTokenPaymasterOracleUsed: string; + entryPoint: string; } \ No newline at end of file diff --git a/backend/src/utils/monitorTokenPaymaster.ts b/backend/src/utils/monitorTokenPaymaster.ts index fc63b8f..ec93c99 100644 --- a/backend/src/utils/monitorTokenPaymaster.ts +++ b/backend/src/utils/monitorTokenPaymaster.ts @@ -5,6 +5,10 @@ import EtherspotAbi from "../abi/EtherspotAbi.js"; export async function checkDeposit(paymasterAddress: string, bundlerUrl: string, webhookUrl: string, thresholdValue: string, chainId: number, log: FastifyBaseLogger) { try { + if (bundlerUrl.includes('testnet')) { + log.info(`Skipping deposit check for testnet on chainId ${chainId} address: ${paymasterAddress} bunderUrl: ${bundlerUrl}`); + return; + } const publicClient = createPublicClient({ transport: http(bundlerUrl) }); const contract = getContract({ address: paymasterAddress as `0x${string}`, abi: EtherspotAbi, client: publicClient }); const currentDeposit = await contract.read.getDeposit();