@aastar/dapp 0.16.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/core/src/abis/BLSAggregator.json +686 -0
- package/dist/core/src/abis/BLSValidator.json +42 -0
- package/dist/core/src/abis/DVTValidator.json +368 -0
- package/dist/core/src/abis/EntryPoint.json +1382 -0
- package/dist/core/src/abis/GToken.json +513 -0
- package/dist/core/src/abis/GTokenStaking.json +949 -0
- package/dist/core/src/abis/MySBT.json +1518 -0
- package/dist/core/src/abis/Paymaster.json +1143 -0
- package/dist/core/src/abis/PaymasterFactory.json +640 -0
- package/dist/core/src/abis/Registry.json +1942 -0
- package/dist/core/src/abis/ReputationSystem.json +699 -0
- package/dist/core/src/abis/SimpleAccount.json +560 -0
- package/dist/core/src/abis/SimpleAccountFactory.json +111 -0
- package/dist/core/src/abis/SuperPaymaster.json +1781 -0
- package/dist/core/src/abis/index.d.ts +1126 -0
- package/dist/core/src/abis/index.js +91 -0
- package/dist/core/src/abis/xPNTsFactory.json +718 -0
- package/dist/core/src/abis/xPNTsToken.json +1280 -0
- package/dist/core/src/actions/StateValidator.d.ts +68 -0
- package/dist/core/src/actions/StateValidator.js +187 -0
- package/dist/core/src/actions/account.d.ts +55 -0
- package/dist/core/src/actions/account.js +133 -0
- package/dist/core/src/actions/aggregator.d.ts +17 -0
- package/dist/core/src/actions/aggregator.js +31 -0
- package/dist/core/src/actions/dvt.d.ts +30 -0
- package/dist/core/src/actions/dvt.js +41 -0
- package/dist/core/src/actions/entryPoint.d.ts +90 -0
- package/dist/core/src/actions/entryPoint.js +211 -0
- package/dist/core/src/actions/factory.d.ts +215 -0
- package/dist/core/src/actions/factory.js +442 -0
- package/dist/core/src/actions/faucet.d.ts +48 -0
- package/dist/core/src/actions/faucet.js +337 -0
- package/dist/core/src/actions/gtokenExtended.d.ts +39 -0
- package/dist/core/src/actions/gtokenExtended.js +115 -0
- package/dist/core/src/actions/index.d.ts +15 -0
- package/dist/core/src/actions/index.js +17 -0
- package/dist/core/src/actions/paymasterV4.d.ts +170 -0
- package/dist/core/src/actions/paymasterV4.js +334 -0
- package/dist/core/src/actions/registry.d.ts +246 -0
- package/dist/core/src/actions/registry.js +667 -0
- package/dist/core/src/actions/reputation.d.ts +129 -0
- package/dist/core/src/actions/reputation.js +281 -0
- package/dist/core/src/actions/sbt.d.ts +191 -0
- package/dist/core/src/actions/sbt.js +533 -0
- package/dist/core/src/actions/staking.d.ts +132 -0
- package/dist/core/src/actions/staking.js +330 -0
- package/dist/core/src/actions/superPaymaster.d.ts +237 -0
- package/dist/core/src/actions/superPaymaster.js +644 -0
- package/dist/core/src/actions/tokens.d.ts +229 -0
- package/dist/core/src/actions/tokens.js +415 -0
- package/dist/core/src/branding.d.ts +30 -0
- package/dist/core/src/branding.js +30 -0
- package/dist/core/src/clients/BaseClient.d.ts +25 -0
- package/dist/core/src/clients/BaseClient.js +66 -0
- package/dist/core/src/clients/types.d.ts +60 -0
- package/dist/core/src/clients/types.js +1 -0
- package/dist/core/src/clients.d.ts +5 -0
- package/dist/core/src/clients.js +11 -0
- package/dist/core/src/communities.d.ts +52 -0
- package/dist/core/src/communities.js +73 -0
- package/dist/core/src/config/ContractConfigManager.d.ts +20 -0
- package/dist/core/src/config/ContractConfigManager.js +48 -0
- package/dist/core/src/constants.d.ts +88 -0
- package/dist/core/src/constants.js +125 -0
- package/dist/core/src/contract-addresses.d.ts +110 -0
- package/dist/core/src/contract-addresses.js +99 -0
- package/dist/core/src/contracts.d.ts +424 -0
- package/dist/core/src/contracts.js +343 -0
- package/dist/core/src/crypto/blsSigner.d.ts +64 -0
- package/dist/core/src/crypto/blsSigner.js +98 -0
- package/dist/core/src/crypto/index.d.ts +1 -0
- package/dist/core/src/crypto/index.js +1 -0
- package/dist/core/src/index.d.ts +21 -0
- package/dist/core/src/index.js +21 -0
- package/dist/core/src/networks.d.ts +127 -0
- package/dist/core/src/networks.js +118 -0
- package/dist/core/src/requirementChecker.d.ts +38 -0
- package/dist/core/src/requirementChecker.js +139 -0
- package/dist/core/src/roles.d.ts +204 -0
- package/dist/core/src/roles.js +211 -0
- package/dist/core/src/utils/validation.d.ts +24 -0
- package/dist/core/src/utils/validation.js +56 -0
- package/dist/dapp/src/index.d.ts +3 -0
- package/dist/dapp/src/index.js +3 -0
- package/dist/dapp/src/ui/components/EvaluationPanel.d.ts +11 -0
- package/dist/dapp/src/ui/components/EvaluationPanel.js +37 -0
- package/dist/dapp/src/ui/hooks/useCreditScore.d.ts +13 -0
- package/dist/dapp/src/ui/hooks/useCreditScore.js +32 -0
- package/dist/dapp/src/ui/hooks/useSuperPaymaster.d.ts +8 -0
- package/dist/dapp/src/ui/hooks/useSuperPaymaster.js +23 -0
- package/dist/dapp/src/ui/index.d.ts +4 -0
- package/dist/dapp/src/ui/index.js +17 -0
- package/dist/paymaster/src/SuperPaymaster/index.d.ts +44 -0
- package/dist/paymaster/src/SuperPaymaster/index.js +133 -0
- package/dist/paymaster/src/V4/PaymasterClient.d.ts +79 -0
- package/dist/paymaster/src/V4/PaymasterClient.js +315 -0
- package/dist/paymaster/src/V4/PaymasterOperator.d.ts +41 -0
- package/dist/paymaster/src/V4/PaymasterOperator.js +241 -0
- package/dist/paymaster/src/V4/PaymasterUtils.d.ts +55 -0
- package/dist/paymaster/src/V4/PaymasterUtils.js +124 -0
- package/dist/paymaster/src/V4/SuperPaymasterClient.d.ts +21 -0
- package/dist/paymaster/src/V4/SuperPaymasterClient.js +73 -0
- package/dist/paymaster/src/V4/index.d.ts +4 -0
- package/dist/paymaster/src/V4/index.js +4 -0
- package/dist/paymaster/src/index.d.ts +2 -0
- package/dist/paymaster/src/index.js +4 -0
- package/package.json +31 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type Address, type Hex } from 'viem';
|
|
2
|
+
/**
|
|
3
|
+
* PaymasterClient
|
|
4
|
+
* Focus: Integration, Funding, Interaction.
|
|
5
|
+
*/
|
|
6
|
+
export declare class PaymasterClient {
|
|
7
|
+
/**
|
|
8
|
+
* Get user's deposited balance on the Paymaster.
|
|
9
|
+
*/
|
|
10
|
+
static getDepositedBalance(publicClient: any, address: Address, user: Address, token: Address): Promise<bigint>;
|
|
11
|
+
/**
|
|
12
|
+
* Deposit tokens to Paymaster for a user (enables gasless transactions).
|
|
13
|
+
*/
|
|
14
|
+
static depositFor(wallet: any, address: Address, user: Address, token: Address, amount: bigint): Promise<any>;
|
|
15
|
+
/**
|
|
16
|
+
* Approve the Paymaster (or any spender) to spend gas tokens.
|
|
17
|
+
*/
|
|
18
|
+
static approveGasToken(wallet: any, token: Address, spender: Address, amount: bigint): Promise<any>;
|
|
19
|
+
/**
|
|
20
|
+
* Estimate Gas for a UserOperation.
|
|
21
|
+
*/
|
|
22
|
+
static estimateUserOperationGas(client: any, wallet: any, aaAddress: Address, entryPoint: Address, paymasterAddress: Address, token: Address, bundlerUrl: string, callData: `0x${string}`, options?: {
|
|
23
|
+
validityWindow?: number;
|
|
24
|
+
operator?: Address;
|
|
25
|
+
factory?: Address;
|
|
26
|
+
factoryData?: Hex;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
preVerificationGas: bigint;
|
|
29
|
+
verificationGasLimit: bigint;
|
|
30
|
+
callGasLimit: bigint;
|
|
31
|
+
paymasterVerificationGasLimit: bigint | undefined;
|
|
32
|
+
paymasterPostOpGasLimit: bigint;
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* High-level API to submit a gasless UserOperation.
|
|
36
|
+
* Automatically handles nonce fetching, gas estimation (if not provided), signing, and submission.
|
|
37
|
+
*/
|
|
38
|
+
static submitGaslessUserOperation(client: any, wallet: any, aaAddress: Address, entryPoint: Address, paymasterAddress: Address, token: Address, bundlerUrl: string, callData: `0x${string}`, options?: {
|
|
39
|
+
validityWindow?: number;
|
|
40
|
+
verificationGasLimit?: bigint;
|
|
41
|
+
callGasLimit?: bigint;
|
|
42
|
+
preVerificationGas?: bigint;
|
|
43
|
+
maxFeePerGas?: bigint;
|
|
44
|
+
maxPriorityFeePerGas?: bigint;
|
|
45
|
+
autoEstimate?: boolean;
|
|
46
|
+
operator?: Address;
|
|
47
|
+
paymasterVerificationGasLimit?: bigint;
|
|
48
|
+
paymasterPostOpGasLimit?: bigint;
|
|
49
|
+
factory?: Address;
|
|
50
|
+
factoryData?: Hex;
|
|
51
|
+
}): Promise<`0x${string}`>;
|
|
52
|
+
/**
|
|
53
|
+
* Helper to extract the actual Gas Token fee from a UserOperation receipt.
|
|
54
|
+
* Looks for the 'PostOpProcessed' event emitted by the Paymaster.
|
|
55
|
+
*/
|
|
56
|
+
static getFeeFromReceipt(receipt: any, paymasterAddress: Address): {
|
|
57
|
+
tokenCost: bigint;
|
|
58
|
+
actualGasCostWei: bigint;
|
|
59
|
+
} | null;
|
|
60
|
+
/**
|
|
61
|
+
* Get the fee for a specific transaction hash.
|
|
62
|
+
* Fetches the receipt (no scanning required) and decodes the log.
|
|
63
|
+
*/
|
|
64
|
+
static getTransactionFee(publicClient: any, txHash: `0x${string}`, paymasterAddress: Address): Promise<{
|
|
65
|
+
tokenCost: bigint;
|
|
66
|
+
actualGasCostWei: bigint;
|
|
67
|
+
} | null>;
|
|
68
|
+
/**
|
|
69
|
+
* Helper: Encode a standardized ERC-20 Transfer.
|
|
70
|
+
* Returns the raw function data: `transfer(to, amount)`
|
|
71
|
+
*/
|
|
72
|
+
static encodeTokenTransfer(recipient: Address, amount: bigint): `0x${string}`;
|
|
73
|
+
/**
|
|
74
|
+
* Helper: Encode a SimpleAccount execution.
|
|
75
|
+
* Wraps the inner call into: `execute(target, value, data)`
|
|
76
|
+
* This is the payload signed by the user.
|
|
77
|
+
*/
|
|
78
|
+
static encodeExecution(target: Address, value: bigint, data: `0x${string}`): `0x${string}`;
|
|
79
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { concat, pad, toHex, parseAbi, encodeFunctionData } from 'viem';
|
|
2
|
+
import { buildPaymasterData, buildSuperPaymasterData, formatUserOpV07, getUserOpHashV07 } from './PaymasterUtils';
|
|
3
|
+
/**
|
|
4
|
+
* PaymasterClient
|
|
5
|
+
* Focus: Integration, Funding, Interaction.
|
|
6
|
+
*/
|
|
7
|
+
export class PaymasterClient {
|
|
8
|
+
/**
|
|
9
|
+
* Get user's deposited balance on the Paymaster.
|
|
10
|
+
*/
|
|
11
|
+
static async getDepositedBalance(publicClient, address, user, token) {
|
|
12
|
+
return publicClient.readContract({
|
|
13
|
+
address,
|
|
14
|
+
abi: [{
|
|
15
|
+
name: 'balances',
|
|
16
|
+
type: 'function',
|
|
17
|
+
inputs: [
|
|
18
|
+
{ name: 'user', type: 'address' },
|
|
19
|
+
{ name: 'token', type: 'address' }
|
|
20
|
+
],
|
|
21
|
+
outputs: [{ name: '', type: 'uint256' }],
|
|
22
|
+
stateMutability: 'view'
|
|
23
|
+
}],
|
|
24
|
+
functionName: 'balances',
|
|
25
|
+
args: [user, token]
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Deposit tokens to Paymaster for a user (enables gasless transactions).
|
|
30
|
+
*/
|
|
31
|
+
static async depositFor(wallet, address, user, token, amount) {
|
|
32
|
+
return wallet.writeContract({
|
|
33
|
+
address,
|
|
34
|
+
abi: parseAbi(['function depositFor(address user, address token, uint256 amount) external']),
|
|
35
|
+
functionName: 'depositFor',
|
|
36
|
+
args: [user, token, amount],
|
|
37
|
+
chain: wallet.chain
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Approve the Paymaster (or any spender) to spend gas tokens.
|
|
42
|
+
*/
|
|
43
|
+
static async approveGasToken(wallet, token, spender, amount) {
|
|
44
|
+
return wallet.writeContract({
|
|
45
|
+
address: token,
|
|
46
|
+
abi: parseAbi(['function approve(address spender, uint256 amount) external returns (bool)']),
|
|
47
|
+
functionName: 'approve',
|
|
48
|
+
args: [spender, amount],
|
|
49
|
+
chain: wallet.chain
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Estimate Gas for a UserOperation.
|
|
54
|
+
*/
|
|
55
|
+
static async estimateUserOperationGas(client, wallet, aaAddress, entryPoint, paymasterAddress, token, bundlerUrl, callData, options) {
|
|
56
|
+
// 1. Construct a dummy UserOp for estimation
|
|
57
|
+
let paymasterAndData;
|
|
58
|
+
if (options?.operator) {
|
|
59
|
+
paymasterAndData = buildSuperPaymasterData(paymasterAddress, options.operator, {
|
|
60
|
+
verificationGasLimit: 300000n,
|
|
61
|
+
postOpGasLimit: 300000n
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
paymasterAndData = buildPaymasterData(paymasterAddress, token, {
|
|
66
|
+
validityWindow: options?.validityWindow,
|
|
67
|
+
verificationGasLimit: 60000n, // Placeholder
|
|
68
|
+
postOpGasLimit: 60000n // Placeholder
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// 1.5. Get dynamic gas prices from network
|
|
72
|
+
let maxFeePerGas = 30000000000n; // 30 Gwei default
|
|
73
|
+
let maxPriorityFeePerGas = 1000000000n; // 1 Gwei default
|
|
74
|
+
try {
|
|
75
|
+
const feeData = await client.estimateFeesPerGas();
|
|
76
|
+
maxFeePerGas = (feeData.maxFeePerGas ?? 30000000000n) * 150n / 100n; // 1.5x buffer
|
|
77
|
+
maxPriorityFeePerGas = (feeData.maxPriorityFeePerGas ?? 1000000000n) * 150n / 100n;
|
|
78
|
+
if (maxPriorityFeePerGas < 500000000n)
|
|
79
|
+
maxPriorityFeePerGas = 500000000n; // Min 0.5 Gwei
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
// Use defaults if estimation fails
|
|
83
|
+
}
|
|
84
|
+
const partialUserOp = {
|
|
85
|
+
sender: aaAddress,
|
|
86
|
+
nonce: 0n,
|
|
87
|
+
initCode: (options?.factory && options?.factoryData)
|
|
88
|
+
? concat([options.factory, options.factoryData])
|
|
89
|
+
: '0x',
|
|
90
|
+
callData,
|
|
91
|
+
accountGasLimits: concat([pad(toHex(60000n), { size: 16 }), pad(toHex(100000n), { size: 16 })]), // 60k verification, 100k call
|
|
92
|
+
preVerificationGas: 50000n, // 50k PVG
|
|
93
|
+
gasFees: concat([pad(toHex(maxPriorityFeePerGas), { size: 16 }), pad(toHex(maxFeePerGas), { size: 16 })]),
|
|
94
|
+
paymasterAndData,
|
|
95
|
+
signature: '0x'
|
|
96
|
+
};
|
|
97
|
+
// Get actual nonce
|
|
98
|
+
try {
|
|
99
|
+
const nonce = await client.readContract({
|
|
100
|
+
address: aaAddress,
|
|
101
|
+
abi: parseAbi(['function getNonce() view returns (uint256)']),
|
|
102
|
+
functionName: 'getNonce'
|
|
103
|
+
});
|
|
104
|
+
partialUserOp.nonce = BigInt(nonce);
|
|
105
|
+
}
|
|
106
|
+
catch (e) { }
|
|
107
|
+
const userOpHash = getUserOpHashV07(partialUserOp, entryPoint, BigInt(client.chain.id));
|
|
108
|
+
partialUserOp.signature = (await wallet.account.signMessage({ message: { raw: userOpHash } }));
|
|
109
|
+
const payload = {
|
|
110
|
+
jsonrpc: '2.0',
|
|
111
|
+
id: 1,
|
|
112
|
+
method: 'eth_estimateUserOperationGas',
|
|
113
|
+
params: [formatUserOpV07(partialUserOp), entryPoint]
|
|
114
|
+
};
|
|
115
|
+
const response = await fetch(bundlerUrl, {
|
|
116
|
+
method: 'POST',
|
|
117
|
+
headers: { 'Content-Type': 'application/json' },
|
|
118
|
+
body: JSON.stringify(payload, (_, v) => typeof v === 'bigint' ? '0x' + v.toString(16) : v)
|
|
119
|
+
});
|
|
120
|
+
const result = await response.json();
|
|
121
|
+
if (result.error)
|
|
122
|
+
throw new Error(`Estimation Error: ${JSON.stringify(result.error)}`);
|
|
123
|
+
const data = result.result;
|
|
124
|
+
// Dynamic tuning based on "Efficiency Guard" formulas
|
|
125
|
+
return {
|
|
126
|
+
preVerificationGas: BigInt(data.preVerificationGas),
|
|
127
|
+
verificationGasLimit: BigInt(data.verificationGasLimit),
|
|
128
|
+
callGasLimit: (BigInt(data.callGasLimit) * 110n) / 100n, // 1.1x safety buffer
|
|
129
|
+
paymasterVerificationGasLimit: data.paymasterVerificationGasLimit ? BigInt(data.paymasterVerificationGasLimit) : undefined,
|
|
130
|
+
paymasterPostOpGasLimit: data.paymasterPostOpGasLimit ? BigInt(data.paymasterPostOpGasLimit) : 100000n
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* High-level API to submit a gasless UserOperation.
|
|
135
|
+
* Automatically handles nonce fetching, gas estimation (if not provided), signing, and submission.
|
|
136
|
+
*/
|
|
137
|
+
static async submitGaslessUserOperation(client, wallet, aaAddress, entryPoint, paymasterAddress, token, bundlerUrl, callData, options) {
|
|
138
|
+
// 0. Auto-Estimate if requested or if limits missing
|
|
139
|
+
let gasLimits = {
|
|
140
|
+
preVerificationGas: options?.preVerificationGas,
|
|
141
|
+
verificationGasLimit: options?.verificationGasLimit,
|
|
142
|
+
callGasLimit: options?.callGasLimit,
|
|
143
|
+
paymasterVerificationGasLimit: options?.paymasterVerificationGasLimit,
|
|
144
|
+
paymasterPostOpGasLimit: options?.paymasterPostOpGasLimit ?? 100000n
|
|
145
|
+
};
|
|
146
|
+
if (options?.autoEstimate !== false && (!gasLimits.verificationGasLimit || !gasLimits.callGasLimit)) {
|
|
147
|
+
const est = await this.estimateUserOperationGas(client, wallet, aaAddress, entryPoint, paymasterAddress, token, bundlerUrl, callData, {
|
|
148
|
+
validityWindow: options?.validityWindow,
|
|
149
|
+
operator: options?.operator,
|
|
150
|
+
factory: options?.factory,
|
|
151
|
+
factoryData: options?.factoryData
|
|
152
|
+
});
|
|
153
|
+
gasLimits.preVerificationGas = options?.preVerificationGas ?? est.preVerificationGas;
|
|
154
|
+
gasLimits.verificationGasLimit = options?.verificationGasLimit ?? est.verificationGasLimit;
|
|
155
|
+
gasLimits.callGasLimit = options?.callGasLimit ?? est.callGasLimit;
|
|
156
|
+
gasLimits.paymasterVerificationGasLimit = options?.paymasterVerificationGasLimit ?? est.paymasterVerificationGasLimit;
|
|
157
|
+
gasLimits.paymasterPostOpGasLimit = options?.paymasterPostOpGasLimit ?? est.paymasterPostOpGasLimit;
|
|
158
|
+
}
|
|
159
|
+
// 1. Get Nonce
|
|
160
|
+
const nonce = await client.readContract({
|
|
161
|
+
address: aaAddress,
|
|
162
|
+
abi: parseAbi(['function getNonce() view returns (uint256)']),
|
|
163
|
+
functionName: 'getNonce'
|
|
164
|
+
});
|
|
165
|
+
// 1.5 Get Gas Prices from Network if not provided
|
|
166
|
+
let maxFeePerGas = options?.maxFeePerGas;
|
|
167
|
+
let maxPriorityFeePerGas = options?.maxPriorityFeePerGas;
|
|
168
|
+
if (!maxFeePerGas || !maxPriorityFeePerGas) {
|
|
169
|
+
try {
|
|
170
|
+
const feeData = await client.estimateFeesPerGas();
|
|
171
|
+
// Apply 1.5x buffer for network volatility
|
|
172
|
+
maxFeePerGas = maxFeePerGas ?? ((feeData.maxFeePerGas ?? 30000000000n) * 150n) / 100n;
|
|
173
|
+
maxPriorityFeePerGas = maxPriorityFeePerGas ?? ((feeData.maxPriorityFeePerGas ?? 1000000000n) * 150n) / 100n;
|
|
174
|
+
if (maxPriorityFeePerGas < 500000000n) {
|
|
175
|
+
console.log(`[PaymasterClient] Priority Fee ${maxPriorityFeePerGas} too low, clamping to 0.5 Gwei`);
|
|
176
|
+
maxPriorityFeePerGas = 500000000n; // Min 0.5 Gwei
|
|
177
|
+
}
|
|
178
|
+
// Ensure MaxFee >= Priority
|
|
179
|
+
if (maxFeePerGas < maxPriorityFeePerGas) {
|
|
180
|
+
maxFeePerGas = maxPriorityFeePerGas + 1000000n; // Add small buffer
|
|
181
|
+
console.log(`[PaymasterClient] MaxFee bumped to accommodate Priority Fee`);
|
|
182
|
+
}
|
|
183
|
+
console.log(`[PaymasterClient] Fees Set: MaxFee=${maxFeePerGas}, Priority=${maxPriorityFeePerGas}`);
|
|
184
|
+
}
|
|
185
|
+
catch (e) {
|
|
186
|
+
console.log('[PaymasterClient] Fee Estimation Failed:', e);
|
|
187
|
+
// Fallback to safer defaults if estimation fails
|
|
188
|
+
maxFeePerGas = maxFeePerGas ?? 50000000000n; // 50 Gwei
|
|
189
|
+
maxPriorityFeePerGas = maxPriorityFeePerGas ?? 2000000000n; // 2 Gwei
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// 2. Build paymasterAndData
|
|
193
|
+
let paymasterAndData;
|
|
194
|
+
if (options?.operator) {
|
|
195
|
+
paymasterAndData = buildSuperPaymasterData(paymasterAddress, options.operator, {
|
|
196
|
+
verificationGasLimit: gasLimits.paymasterVerificationGasLimit ?? gasLimits.verificationGasLimit ?? 150000n,
|
|
197
|
+
postOpGasLimit: gasLimits.paymasterPostOpGasLimit ?? 100000n
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
paymasterAndData = buildPaymasterData(paymasterAddress, token, {
|
|
202
|
+
validityWindow: options?.validityWindow,
|
|
203
|
+
verificationGasLimit: gasLimits.paymasterVerificationGasLimit ?? gasLimits.verificationGasLimit ?? 150000n, // Use tuned value
|
|
204
|
+
postOpGasLimit: gasLimits.paymasterPostOpGasLimit ?? 100000n
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
// 3. Construct UserOp
|
|
208
|
+
const userOp = {
|
|
209
|
+
sender: aaAddress,
|
|
210
|
+
nonce: BigInt(nonce),
|
|
211
|
+
initCode: (options?.factory && options?.factoryData)
|
|
212
|
+
? concat([options.factory, options.factoryData])
|
|
213
|
+
: '0x',
|
|
214
|
+
callData,
|
|
215
|
+
accountGasLimits: concat([
|
|
216
|
+
pad(toHex(gasLimits.verificationGasLimit ?? 150000n), { size: 16 }), // Verification (Tuned or Default)
|
|
217
|
+
pad(toHex(gasLimits.callGasLimit ?? 500000n), { size: 16 }) // Call (Tuned or Default)
|
|
218
|
+
]),
|
|
219
|
+
preVerificationGas: gasLimits.preVerificationGas ?? 50000n,
|
|
220
|
+
gasFees: concat([
|
|
221
|
+
pad(toHex(maxPriorityFeePerGas), { size: 16 }),
|
|
222
|
+
pad(toHex(maxFeePerGas), { size: 16 })
|
|
223
|
+
]),
|
|
224
|
+
paymasterAndData,
|
|
225
|
+
signature: '0x'
|
|
226
|
+
};
|
|
227
|
+
// Debug logs (Commented out for production)
|
|
228
|
+
/*
|
|
229
|
+
console.log("DEBUG: UserOp Gas Limits:", {
|
|
230
|
+
accountGasLimits: userOp.accountGasLimits,
|
|
231
|
+
preVerificationGas: userOp.preVerificationGas,
|
|
232
|
+
gasFees: userOp.gasFees,
|
|
233
|
+
paymasterAndData: userOp.paymasterAndData
|
|
234
|
+
});
|
|
235
|
+
*/
|
|
236
|
+
// 4. Final Hashing and Signing
|
|
237
|
+
const userOpHash = getUserOpHashV07(userOp, entryPoint, BigInt(client.chain.id));
|
|
238
|
+
const signature = (await wallet.account.signMessage({ message: { raw: userOpHash } }));
|
|
239
|
+
userOp.signature = signature;
|
|
240
|
+
// 6. Submit to Bundler
|
|
241
|
+
const response = await fetch(bundlerUrl, {
|
|
242
|
+
method: 'POST',
|
|
243
|
+
headers: { 'Content-Type': 'application/json' },
|
|
244
|
+
body: JSON.stringify({
|
|
245
|
+
jsonrpc: '2.0',
|
|
246
|
+
id: 1,
|
|
247
|
+
method: 'eth_sendUserOperation',
|
|
248
|
+
params: [formatUserOpV07(userOp), entryPoint]
|
|
249
|
+
}, (_, v) => typeof v === 'bigint' ? '0x' + v.toString(16) : v)
|
|
250
|
+
});
|
|
251
|
+
const result = await response.json();
|
|
252
|
+
if (result.error)
|
|
253
|
+
throw new Error(`Bundler Error: ${JSON.stringify(result.error)}`);
|
|
254
|
+
return result.result;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Helper to extract the actual Gas Token fee from a UserOperation receipt.
|
|
258
|
+
* Looks for the 'PostOpProcessed' event emitted by the Paymaster.
|
|
259
|
+
*/
|
|
260
|
+
static getFeeFromReceipt(receipt, paymasterAddress) {
|
|
261
|
+
// Event Signature: PostOpProcessed(address indexed user, address indexed token, uint256 actualGasCostWei, uint256 tokenCost, uint256 protocolRevenue)
|
|
262
|
+
// Topic0: 0x62544d7f48b11c32334310ebd306b47224fca220163218d4a7264322c52ae073
|
|
263
|
+
const TOPIC_POST_OP = '0x62544d7f48b11c32334310ebd306b47224fca220163218d4a7264322c52ae073';
|
|
264
|
+
for (const log of receipt.logs) {
|
|
265
|
+
if (log.address.toLowerCase() === paymasterAddress.toLowerCase() && log.topics[0] === TOPIC_POST_OP) {
|
|
266
|
+
// Decode Data: actualGasCostWei, tokenCost, protocolRevenue (3x uint256)
|
|
267
|
+
// We manually decode or use viem's decodeEventLog if available.
|
|
268
|
+
// Here we use a lightweight manual decode for the data part (non-indexed).
|
|
269
|
+
// Data is 3 * 32 bytes.
|
|
270
|
+
const data = log.data.replace('0x', '');
|
|
271
|
+
if (data.length >= 192) { // 3 * 64 hex chars = 192
|
|
272
|
+
const actualGasCostWei = BigInt('0x' + data.slice(0, 64));
|
|
273
|
+
const tokenCost = BigInt('0x' + data.slice(64, 128));
|
|
274
|
+
// const protocolRevenue = BigInt('0x' + data.slice(128, 192));
|
|
275
|
+
return { tokenCost, actualGasCostWei };
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Get the fee for a specific transaction hash.
|
|
283
|
+
* Fetches the receipt (no scanning required) and decodes the log.
|
|
284
|
+
*/
|
|
285
|
+
static async getTransactionFee(publicClient, txHash, paymasterAddress) {
|
|
286
|
+
const receipt = await publicClient.getTransactionReceipt({ hash: txHash });
|
|
287
|
+
return this.getFeeFromReceipt(receipt, paymasterAddress);
|
|
288
|
+
}
|
|
289
|
+
// ===========================================
|
|
290
|
+
// 🛠️ Semantic CallData Builders (For DX)
|
|
291
|
+
// ===========================================
|
|
292
|
+
/**
|
|
293
|
+
* Helper: Encode a standardized ERC-20 Transfer.
|
|
294
|
+
* Returns the raw function data: `transfer(to, amount)`
|
|
295
|
+
*/
|
|
296
|
+
static encodeTokenTransfer(recipient, amount) {
|
|
297
|
+
return encodeFunctionData({
|
|
298
|
+
abi: parseAbi(['function transfer(address to, uint256 amount) external returns (bool)']),
|
|
299
|
+
functionName: 'transfer',
|
|
300
|
+
args: [recipient, amount]
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Helper: Encode a SimpleAccount execution.
|
|
305
|
+
* Wraps the inner call into: `execute(target, value, data)`
|
|
306
|
+
* This is the payload signed by the user.
|
|
307
|
+
*/
|
|
308
|
+
static encodeExecution(target, value, data) {
|
|
309
|
+
return encodeFunctionData({
|
|
310
|
+
abi: parseAbi(['function execute(address dest, uint256 value, bytes func) external']),
|
|
311
|
+
functionName: 'execute',
|
|
312
|
+
args: [target, value, data]
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type Address } from 'viem';
|
|
2
|
+
import { type GaslessReadinessReport } from './PaymasterUtils';
|
|
3
|
+
/**
|
|
4
|
+
* PaymasterOperator
|
|
5
|
+
* Focus: Deployment, Configuration, Maintenance, Keeper Bots.
|
|
6
|
+
*/
|
|
7
|
+
export declare class PaymasterOperator {
|
|
8
|
+
/**
|
|
9
|
+
* Update the cached ETH/USD price from Chainlink Oracle.
|
|
10
|
+
* Must be called if cachedPrice is 0 (uninitialized).
|
|
11
|
+
*/
|
|
12
|
+
static updatePrice(wallet: any, address: Address): Promise<any>;
|
|
13
|
+
/**
|
|
14
|
+
* Set the token price (in 8 decimals, e.g., 1e8 = $1 USD).
|
|
15
|
+
*/
|
|
16
|
+
static setTokenPrice(wallet: any, address: Address, token: Address, priceUSD: bigint): Promise<any>;
|
|
17
|
+
static getCachedPrice(publicClient: any, address: Address): Promise<{
|
|
18
|
+
price: bigint;
|
|
19
|
+
updatedAt: bigint;
|
|
20
|
+
}>;
|
|
21
|
+
static getTokenPrice(publicClient: any, address: Address, token: Address): Promise<bigint>;
|
|
22
|
+
static getDepositedBalance(publicClient: any, address: Address, user: Address, token: Address): Promise<bigint>;
|
|
23
|
+
static ensurePriceInitialized(wallet: any, publicClient: any, address: Address): Promise<boolean>;
|
|
24
|
+
static addStake(wallet: any, address: Address, amount: bigint, unstakeDelaySec: number): Promise<any>;
|
|
25
|
+
static addDeposit(wallet: any, address: Address, amount: bigint): Promise<any>;
|
|
26
|
+
static addGasToken(wallet: any, address: Address, token: Address): Promise<any>;
|
|
27
|
+
static removeGasToken(wallet: any, address: Address, token: Address): Promise<any>;
|
|
28
|
+
static setServiceFeeRate(wallet: any, address: Address, rate: bigint): Promise<any>;
|
|
29
|
+
static setMaxGasCostCap(wallet: any, address: Address, cap: bigint): Promise<any>;
|
|
30
|
+
static withdrawPNT(wallet: any, address: Address, to: Address, token: Address, amount: bigint): Promise<any>;
|
|
31
|
+
static checkGaslessReadiness(publicClient: any, entryPoint: Address, paymasterAddress: Address, user: Address, token: Address): Promise<GaslessReadinessReport>;
|
|
32
|
+
static prepareGaslessEnvironment(operatorWallet: any, publicClient: any, entryPoint: Address, paymasterAddress: Address, token: Address, options?: {
|
|
33
|
+
minStake?: bigint;
|
|
34
|
+
minDeposit?: bigint;
|
|
35
|
+
tokenPriceUSD?: bigint;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
step: string;
|
|
38
|
+
hash?: string;
|
|
39
|
+
status: string;
|
|
40
|
+
}[]>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { parseAbi } from 'viem';
|
|
2
|
+
/**
|
|
3
|
+
* PaymasterOperator
|
|
4
|
+
* Focus: Deployment, Configuration, Maintenance, Keeper Bots.
|
|
5
|
+
*/
|
|
6
|
+
export class PaymasterOperator {
|
|
7
|
+
/**
|
|
8
|
+
* Update the cached ETH/USD price from Chainlink Oracle.
|
|
9
|
+
* Must be called if cachedPrice is 0 (uninitialized).
|
|
10
|
+
*/
|
|
11
|
+
static async updatePrice(wallet, address) {
|
|
12
|
+
return wallet.writeContract({
|
|
13
|
+
address,
|
|
14
|
+
abi: parseAbi(['function updatePrice() external']),
|
|
15
|
+
functionName: 'updatePrice',
|
|
16
|
+
chain: wallet.chain
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Set the token price (in 8 decimals, e.g., 1e8 = $1 USD).
|
|
21
|
+
*/
|
|
22
|
+
static async setTokenPrice(wallet, address, token, priceUSD) {
|
|
23
|
+
return wallet.writeContract({
|
|
24
|
+
address,
|
|
25
|
+
abi: parseAbi(['function setTokenPrice(address token, uint256 price) external']),
|
|
26
|
+
functionName: 'setTokenPrice',
|
|
27
|
+
args: [token, priceUSD],
|
|
28
|
+
chain: wallet.chain
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
static async getCachedPrice(publicClient, address) {
|
|
32
|
+
const result = await publicClient.readContract({
|
|
33
|
+
address,
|
|
34
|
+
abi: [{
|
|
35
|
+
name: 'cachedPrice',
|
|
36
|
+
type: 'function',
|
|
37
|
+
inputs: [],
|
|
38
|
+
outputs: [
|
|
39
|
+
{ name: 'price', type: 'uint208' },
|
|
40
|
+
{ name: 'updatedAt', type: 'uint48' }
|
|
41
|
+
],
|
|
42
|
+
stateMutability: 'view'
|
|
43
|
+
}],
|
|
44
|
+
functionName: 'cachedPrice'
|
|
45
|
+
});
|
|
46
|
+
return { price: result[0], updatedAt: result[1] };
|
|
47
|
+
}
|
|
48
|
+
static async getTokenPrice(publicClient, address, token) {
|
|
49
|
+
return publicClient.readContract({
|
|
50
|
+
address,
|
|
51
|
+
abi: [{
|
|
52
|
+
name: 'tokenPrices',
|
|
53
|
+
type: 'function',
|
|
54
|
+
inputs: [{ name: 'token', type: 'address' }],
|
|
55
|
+
outputs: [{ name: '', type: 'uint256' }],
|
|
56
|
+
stateMutability: 'view'
|
|
57
|
+
}],
|
|
58
|
+
functionName: 'tokenPrices',
|
|
59
|
+
args: [token]
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
static async getDepositedBalance(publicClient, address, user, token) {
|
|
63
|
+
return publicClient.readContract({
|
|
64
|
+
address,
|
|
65
|
+
abi: [{
|
|
66
|
+
name: 'balances',
|
|
67
|
+
type: 'function',
|
|
68
|
+
inputs: [
|
|
69
|
+
{ name: 'user', type: 'address' },
|
|
70
|
+
{ name: 'token', type: 'address' }
|
|
71
|
+
],
|
|
72
|
+
outputs: [{ name: '', type: 'uint256' }],
|
|
73
|
+
stateMutability: 'view'
|
|
74
|
+
}],
|
|
75
|
+
functionName: 'balances',
|
|
76
|
+
args: [user, token]
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
static async ensurePriceInitialized(wallet, publicClient, address) {
|
|
80
|
+
const { price } = await this.getCachedPrice(publicClient, address);
|
|
81
|
+
if (price === 0n) {
|
|
82
|
+
await this.updatePrice(wallet, address);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
static async addStake(wallet, address, amount, unstakeDelaySec) {
|
|
88
|
+
return wallet.writeContract({
|
|
89
|
+
address,
|
|
90
|
+
abi: parseAbi(['function addStake(uint32 unstakeDelaySec) external payable']),
|
|
91
|
+
functionName: 'addStake',
|
|
92
|
+
args: [unstakeDelaySec],
|
|
93
|
+
value: amount,
|
|
94
|
+
chain: wallet.chain
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
static async addDeposit(wallet, address, amount) {
|
|
98
|
+
return wallet.writeContract({
|
|
99
|
+
address,
|
|
100
|
+
abi: parseAbi(['function addDeposit() external payable']),
|
|
101
|
+
functionName: 'addDeposit',
|
|
102
|
+
value: amount,
|
|
103
|
+
chain: wallet.chain
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
static async addGasToken(wallet, address, token) {
|
|
107
|
+
return wallet.writeContract({
|
|
108
|
+
address,
|
|
109
|
+
abi: ['function addGasToken(address token)'],
|
|
110
|
+
functionName: 'addGasToken',
|
|
111
|
+
args: [token],
|
|
112
|
+
chain: wallet.chain
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
static async removeGasToken(wallet, address, token) {
|
|
116
|
+
return wallet.writeContract({
|
|
117
|
+
address,
|
|
118
|
+
abi: ['function removeGasToken(address token)'],
|
|
119
|
+
functionName: 'removeGasToken',
|
|
120
|
+
args: [token],
|
|
121
|
+
chain: wallet.chain
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
static async setServiceFeeRate(wallet, address, rate) {
|
|
125
|
+
return wallet.writeContract({
|
|
126
|
+
address,
|
|
127
|
+
abi: ['function setServiceFeeRate(uint256 rate)'],
|
|
128
|
+
functionName: 'setServiceFeeRate',
|
|
129
|
+
args: [rate],
|
|
130
|
+
chain: wallet.chain
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
static async setMaxGasCostCap(wallet, address, cap) {
|
|
134
|
+
return wallet.writeContract({
|
|
135
|
+
address,
|
|
136
|
+
abi: ['function setMaxGasCostCap(uint256 cap)'],
|
|
137
|
+
functionName: 'setMaxGasCostCap',
|
|
138
|
+
args: [cap],
|
|
139
|
+
chain: wallet.chain
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
static async withdrawPNT(wallet, address, to, token, amount) {
|
|
143
|
+
return wallet.writeContract({
|
|
144
|
+
address,
|
|
145
|
+
abi: ['function withdrawPNT(address to, address token, uint256 amount)'],
|
|
146
|
+
functionName: 'withdrawPNT',
|
|
147
|
+
args: [to, token, amount],
|
|
148
|
+
chain: wallet.chain
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
// --- Diagnostics & Automation ---
|
|
152
|
+
static async checkGaslessReadiness(publicClient, entryPoint, paymasterAddress, user, token) {
|
|
153
|
+
const issues = [];
|
|
154
|
+
// 1. EntryPoint Stake/Deposit
|
|
155
|
+
const depositInfo = await publicClient.readContract({
|
|
156
|
+
address: entryPoint,
|
|
157
|
+
abi: parseAbi(['function getDepositInfo(address account) external view returns (uint256 deposit, bool staked, uint256 stake, uint32 unstakeDelaySec, uint48 withdrawTime)']),
|
|
158
|
+
functionName: 'getDepositInfo',
|
|
159
|
+
args: [paymasterAddress]
|
|
160
|
+
});
|
|
161
|
+
if (depositInfo[2] < 50000000000000000n)
|
|
162
|
+
issues.push('Paymaster stake in EntryPoint is less than 0.05 ETH');
|
|
163
|
+
if (depositInfo[3] < 86400)
|
|
164
|
+
issues.push('Paymaster unstake delay is less than 1 day');
|
|
165
|
+
if (depositInfo[0] < 100000000000000000n)
|
|
166
|
+
issues.push('Paymaster deposit in EntryPoint is less than 0.1 ETH');
|
|
167
|
+
// 2. Oracle Price
|
|
168
|
+
const ethPrice = await publicClient.readContract({
|
|
169
|
+
address: paymasterAddress,
|
|
170
|
+
abi: parseAbi(['function cachedPrice() external view returns (uint208 price, uint48 updatedAt)']),
|
|
171
|
+
functionName: 'cachedPrice'
|
|
172
|
+
}).catch(() => [0n, 0n]);
|
|
173
|
+
if (ethPrice[0] === 0n)
|
|
174
|
+
issues.push('Paymaster ETH/USD price not initialized');
|
|
175
|
+
// 3. Token Support & Price
|
|
176
|
+
const [tokenPrice, userTokenBal, userPMDeposit] = await Promise.all([
|
|
177
|
+
this.getTokenPrice(publicClient, paymasterAddress, token),
|
|
178
|
+
publicClient.readContract({
|
|
179
|
+
address: token,
|
|
180
|
+
abi: parseAbi(['function balanceOf(address account) external view returns (uint256)']),
|
|
181
|
+
functionName: 'balanceOf',
|
|
182
|
+
args: [user]
|
|
183
|
+
}),
|
|
184
|
+
this.getDepositedBalance(publicClient, paymasterAddress, user, token)
|
|
185
|
+
]);
|
|
186
|
+
if (tokenPrice === 0n)
|
|
187
|
+
issues.push('Token price not set in Paymaster');
|
|
188
|
+
if (userPMDeposit === 0n)
|
|
189
|
+
issues.push('User has no deposit in Paymaster');
|
|
190
|
+
return {
|
|
191
|
+
isReady: issues.length === 0,
|
|
192
|
+
issues,
|
|
193
|
+
details: {
|
|
194
|
+
paymasterStake: depositInfo[2],
|
|
195
|
+
paymasterDeposit: depositInfo[0],
|
|
196
|
+
ethUsdPrice: ethPrice.price,
|
|
197
|
+
tokenSupported: true,
|
|
198
|
+
tokenPrice: tokenPrice,
|
|
199
|
+
userTokenBalance: userTokenBal,
|
|
200
|
+
userPaymasterDeposit: userPMDeposit
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
static async prepareGaslessEnvironment(operatorWallet, publicClient, entryPoint, paymasterAddress, token, options = {}) {
|
|
205
|
+
const report = await this.checkGaslessReadiness(publicClient, entryPoint, paymasterAddress, operatorWallet.account.address, token);
|
|
206
|
+
const results = [];
|
|
207
|
+
// 1. Stake
|
|
208
|
+
if (report.details.paymasterStake < (options.minStake || 50000000000000000n)) {
|
|
209
|
+
const hash = await this.addStake(operatorWallet, paymasterAddress, options.minStake || 50000000000000000n, 86400);
|
|
210
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
211
|
+
results.push({ step: 'Stake', hash, status: 'Confirmed' });
|
|
212
|
+
}
|
|
213
|
+
// 2. Deposit (EntryPoint)
|
|
214
|
+
if (report.details.paymasterDeposit < (options.minDeposit || 100000000000000000n)) {
|
|
215
|
+
const hash = await this.addDeposit(operatorWallet, paymasterAddress, options.minDeposit || 300000000000000000n);
|
|
216
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
217
|
+
results.push({ step: 'Deposit', hash, status: 'Confirmed' });
|
|
218
|
+
}
|
|
219
|
+
// 3. Oracle Price
|
|
220
|
+
if (report.details.ethUsdPrice === 0n) {
|
|
221
|
+
const hash = await this.updatePrice(operatorWallet, paymasterAddress);
|
|
222
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
223
|
+
results.push({ step: 'OraclePrice', hash, status: 'Confirmed' });
|
|
224
|
+
}
|
|
225
|
+
// 4. Token Support & Price
|
|
226
|
+
if (report.details.tokenPrice === 0n) {
|
|
227
|
+
try {
|
|
228
|
+
const hash = await this.addGasToken(operatorWallet, paymasterAddress, token);
|
|
229
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
230
|
+
results.push({ step: 'AddGasToken', hash, status: 'Confirmed' });
|
|
231
|
+
}
|
|
232
|
+
catch (e) { }
|
|
233
|
+
if (options.tokenPriceUSD) {
|
|
234
|
+
const hash = await this.setTokenPrice(operatorWallet, paymasterAddress, token, options.tokenPriceUSD);
|
|
235
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
236
|
+
results.push({ step: 'TokenPrice', hash, status: 'Confirmed' });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return results;
|
|
240
|
+
}
|
|
241
|
+
}
|