Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions backend/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Changelog
## [4.2.2] - 2025-12-09
Comment thread
vignesha22 marked this conversation as resolved.
- 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)
Expand Down
2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down
35 changes: 17 additions & 18 deletions backend/src/paymaster/index.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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
}

Expand All @@ -62,7 +61,7 @@ interface TokenPriceAndMetadataCache {
expiry: number
}

interface NativeCurrencyPricyCache {
interface NativeCurrencyPriceCache {
data: any;
expiry: number;
}
Expand Down Expand Up @@ -97,7 +96,7 @@ export class Paymaster {
MTP_PVGL: string;
MTP_PPGL: string;
priceAndMetadata: Map<string, TokenPriceAndMetadataCache> = new Map();
nativeCurrencyPrice: Map<string, NativeCurrencyPricyCache> = new Map();
nativeCurrencyPrice: Map<string, NativeCurrencyPriceCache> = new Map();
coingeckoPrice: Map<string, CoingeckoPriceCache> = new Map();
coingeckoService: CoingeckoService = new CoingeckoService();
sequelize: Sequelize;
Expand Down Expand Up @@ -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 });
Expand Down Expand Up @@ -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';
Expand Down
1 change: 1 addition & 0 deletions backend/src/plugins/sequelizePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ declare module "fastify" {
sponsorshipPolicyRepository: SponsorshipPolicyRepository;
whitelistRepository: WhitelistRepository;
contractWhitelistRepository: ContractWhitelistRepository;
coingeckoRepo: CoingeckoTokensRepository;
multiTokenPaymasterRepository: MultiTokenPaymasterRepository;
}
}
Expand Down
6 changes: 3 additions & 3 deletions backend/src/routes/admin-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment thread
vignesha22 marked this conversation as resolved.
erc20Paymasters: body.erc20Paymasters,
multiTokenPaymasters: body.multiTokenPaymasters ?? null,
multiTokenOracles: body.multiTokenOracles ?? null,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion backend/src/routes/sponsorship-policy-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
}
Expand Down
12 changes: 6 additions & 6 deletions backend/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> => {
Expand Down Expand Up @@ -314,7 +314,7 @@ const initializeServer = async (): Promise<void> => {
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);
}
}
}
Expand All @@ -335,7 +335,7 @@ const initializeServer = async (): Promise<void> => {
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)
}
}
}
Expand All @@ -349,7 +349,7 @@ const initializeServer = async (): Promise<void> => {
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);
}
}
}
Expand All @@ -359,7 +359,7 @@ const initializeServer = async (): Promise<void> => {
// 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);
}
}

Expand All @@ -368,7 +368,7 @@ const initializeServer = async (): Promise<void> => {
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) {
Expand Down
16 changes: 8 additions & 8 deletions backend/src/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
log.info(methodName, "called: ");
log.info(request.query, "query passed: ");
log.info(request.body, "body passed: ");
Expand Down Expand Up @@ -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 {
Expand All @@ -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 [];
Expand Down
11 changes: 11 additions & 0 deletions backend/src/utils/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
4 changes: 4 additions & 0 deletions backend/src/utils/monitorTokenPaymaster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Comment thread
vignesha22 marked this conversation as resolved.
const publicClient = createPublicClient({ transport: http(bundlerUrl) });
const contract = getContract({ address: paymasterAddress as `0x${string}`, abi: EtherspotAbi, client: publicClient });
const currentDeposit = await contract.read.getDeposit();
Expand Down
Loading