@swimmingkiim/pay-sdk 0.1.22 → 0.1.24
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/PAYMASTER_USAGE.md +12 -6
- package/PAYMENT_VERIFIER_USAGE.md +219 -0
- package/dist/account/smart-account.d.ts.map +1 -1
- package/dist/account/smart-account.js +10 -4
- package/dist/account/smart-account.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/paymaster/paymaster.d.ts +2 -0
- package/dist/paymaster/paymaster.d.ts.map +1 -1
- package/dist/paymaster/paymaster.js +5 -0
- package/dist/paymaster/paymaster.js.map +1 -1
- package/dist/payment/payment-verifier.d.ts +45 -0
- package/dist/payment/payment-verifier.d.ts.map +1 -0
- package/dist/payment/payment-verifier.js +108 -0
- package/dist/payment/payment-verifier.js.map +1 -0
- package/package.json +1 -1
- package/src/account/smart-account.ts +11 -4
- package/src/index.ts +1 -0
- package/src/paymaster/paymaster.ts +6 -0
- package/src/payment/payment-verifier.ts +149 -0
- package/test/auto-deposit.test.ts +5 -5
- package/test/payment-verifier.test.ts +177 -0
- package/test-results.log +83 -0
- package/tsconfig.tsbuildinfo +1 -1
package/PAYMASTER_USAGE.md
CHANGED
|
@@ -104,12 +104,18 @@ console.log("Transaction Hash:", txHash);
|
|
|
104
104
|
|
|
105
105
|
### 5. Auto-Deposit Feature
|
|
106
106
|
|
|
107
|
-
The SDK includes a built-in **Auto-Deposit** mechanism.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
**
|
|
107
|
+
The SDK includes a built-in **Auto-Deposit** mechanism to ensure smooth execution even for new accounts.
|
|
108
|
+
|
|
109
|
+
#### How it works:
|
|
110
|
+
1. **Check**: Before sending a UserOperation, the SDK checks if the Smart Account has enough USDC to cover the Paymaster fee (default fee or custom amount).
|
|
111
|
+
2. **Deposit**: If funds are insufficient, it automatically triggers a standard ETH transaction from the signer's EOA (Externally Owned Account) to the Smart Account to transfer the missing USDC.
|
|
112
|
+
3. **Execute**: Once the deposit transaction is confirmed on-chain, it proceeds with the Paymaster sponsored transaction.
|
|
113
|
+
|
|
114
|
+
#### ⚠️ Important Requirements:
|
|
115
|
+
* **Signer EOA Funds**: Your private key's wallet (EOA) MUST have:
|
|
116
|
+
* **ETH**: To pay gas for the standard deposit transaction (this step is NOT sponsored).
|
|
117
|
+
* **USDC**: Sufficient balance to transfer to the Smart Account.
|
|
118
|
+
* **Permissions**: The EOA must be an owner of the Smart Account (handled automatically during creation).
|
|
113
119
|
|
|
114
120
|
## 🛡️ Error Handling
|
|
115
121
|
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# PaymentVerifier Usage Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
`PaymentVerifier` is a utility class in `@swimmingkiim/pay-sdk` that verifies on-chain ERC20 token transfers. It's designed for implementing "pay-per-use" API patterns.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
The class is already included in `@swimmingkiim/pay-sdk`:
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
import { PaymentVerifier } from '@swimmingkiim/pay-sdk';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Basic Usage
|
|
15
|
+
|
|
16
|
+
### 1. Initialize PaymentVerifier
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { PaymentVerifier } from '@swimmingkiim/pay-sdk';
|
|
20
|
+
import { base } from 'viem/chains';
|
|
21
|
+
|
|
22
|
+
const verifier = new PaymentVerifier({
|
|
23
|
+
rpcUrl: 'https://mainnet.base.org',
|
|
24
|
+
chain: base,
|
|
25
|
+
tokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' // Optional: USDC (default)
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Verify a Payment
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
const result = await verifier.verifyUSDCPayment(
|
|
33
|
+
'0x123...', // Transaction hash
|
|
34
|
+
'0xabc...', // Expected sender
|
|
35
|
+
'0xdef...', // Expected receiver (your treasury)
|
|
36
|
+
100000n // Minimum amount (0.1 USDC)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
if (result.isValid) {
|
|
40
|
+
console.log(`Payment verified: ${result.amount} tokens`);
|
|
41
|
+
} else {
|
|
42
|
+
console.error(`Verification failed: ${result.error}`);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API Reference
|
|
47
|
+
|
|
48
|
+
### `PaymentVerifier`
|
|
49
|
+
|
|
50
|
+
#### Constructor
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
new PaymentVerifier(config: PaymentVerifierConfig)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Config:**
|
|
57
|
+
- `rpcUrl`: Blockchain RPC endpoint
|
|
58
|
+
- `chain`: viem Chain object (e.g., `base`, `mainnet`)
|
|
59
|
+
- `tokenAddress?`: ERC20 token address (defaults to USDC on Base)
|
|
60
|
+
|
|
61
|
+
#### Methods
|
|
62
|
+
|
|
63
|
+
##### `verifyPayment()`
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
async verifyPayment(
|
|
67
|
+
txHash: `0x${string}`,
|
|
68
|
+
expectedFrom: `0x${string}`,
|
|
69
|
+
expectedTo: `0x${string}`,
|
|
70
|
+
minimumAmount: bigint
|
|
71
|
+
): Promise<PaymentVerificationResult>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Verifies an ERC20 transfer transaction.
|
|
75
|
+
|
|
76
|
+
**Returns:**
|
|
77
|
+
```typescript
|
|
78
|
+
{
|
|
79
|
+
isValid: boolean;
|
|
80
|
+
error?: string;
|
|
81
|
+
txHash?: `0x${string}`;
|
|
82
|
+
from?: `0x${string}`;
|
|
83
|
+
to?: `0x${string}`;
|
|
84
|
+
amount?: bigint;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
##### `verifyUSDCPayment()`
|
|
89
|
+
|
|
90
|
+
Convenience method with the same signature as `verifyPayment()` but optimized for USDC verification.
|
|
91
|
+
|
|
92
|
+
## Real-World Example: Paymaster Proxy Server
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import express from 'express';
|
|
96
|
+
import { PaymentVerifier, PaymasterManager } from '@swimmingkiim/pay-sdk';
|
|
97
|
+
import { base } from 'viem/chains';
|
|
98
|
+
|
|
99
|
+
const app = express();
|
|
100
|
+
app.use(express.json());
|
|
101
|
+
|
|
102
|
+
const TREASURY = process.env.TREASURY_ADDRESS as `0x${string}`;
|
|
103
|
+
const verifier = new PaymentVerifier({
|
|
104
|
+
rpcUrl: process.env.RPC_URL!,
|
|
105
|
+
chain: base
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
app.post('/api/sponsor', async (req, res) => {
|
|
109
|
+
const paymentTx = req.headers['x-payment-tx'] as `0x${string}`;
|
|
110
|
+
|
|
111
|
+
if (!paymentTx) {
|
|
112
|
+
return res.status(402).json({ error: 'Payment required' });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Verify payment
|
|
116
|
+
const verification = await verifier.verifyUSDCPayment(
|
|
117
|
+
paymentTx,
|
|
118
|
+
req.body.userOperation.sender,
|
|
119
|
+
TREASURY,
|
|
120
|
+
100000n // 0.1 USDC
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (!verification.isValid) {
|
|
124
|
+
return res.status(402).json({
|
|
125
|
+
error: 'Invalid payment',
|
|
126
|
+
details: verification.error
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Payment verified → provide service
|
|
131
|
+
const sponsorship = await paymasterManager.getStubPaymasterData(
|
|
132
|
+
req.body.userOperation
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
res.json(sponsorship);
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Best Practices
|
|
140
|
+
|
|
141
|
+
### 1. Prevent Payment Reuse
|
|
142
|
+
|
|
143
|
+
Store verified transaction hashes to prevent reuse:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import Redis from 'ioredis';
|
|
147
|
+
const redis = new Redis();
|
|
148
|
+
|
|
149
|
+
// After verification:
|
|
150
|
+
if (verification.isValid) {
|
|
151
|
+
// Check if already used
|
|
152
|
+
const exists = await redis.exists(`payment:${txHash}`);
|
|
153
|
+
if (exists) {
|
|
154
|
+
return { error: 'Payment already used' };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Mark as used (expires in 1 hour)
|
|
158
|
+
await redis.set(`payment:${txHash}`, 'used', 'EX', 3600);
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 2. Time-Based Expiration
|
|
163
|
+
|
|
164
|
+
Only accept recent payments:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
const receipt = await publicClient.getTransactionReceipt({ hash: txHash });
|
|
168
|
+
const block = await publicClient.getBlock({ blockNumber: receipt.blockNumber });
|
|
169
|
+
const txTime = Number(block.timestamp) * 1000;
|
|
170
|
+
const now = Date.now();
|
|
171
|
+
|
|
172
|
+
if (now - txTime > 5 * 60 * 1000) { // 5 minutes
|
|
173
|
+
return { error: 'Payment expired' };
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 3. Credit System
|
|
178
|
+
|
|
179
|
+
Allow overpayment for credits:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
const PRICE_PER_REQUEST = 100000n; // 0.1 USDC
|
|
183
|
+
|
|
184
|
+
if (verification.amount > PRICE_PER_REQUEST) {
|
|
185
|
+
const credits = verification.amount / PRICE_PER_REQUEST;
|
|
186
|
+
await db.addCredits(userAddress, Number(credits));
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Error Handling
|
|
191
|
+
|
|
192
|
+
Common errors returned in `PaymentVerificationResult.error`:
|
|
193
|
+
|
|
194
|
+
- `"Transaction not found"`: Invalid transaction hash
|
|
195
|
+
- `"Transaction failed"`: Transaction reverted on-chain
|
|
196
|
+
- `"No transfer events found for this token"`: Wrong token or no transfer occurred
|
|
197
|
+
- `"No matching transfer found in transaction"`: Transfer exists but doesn't match criteria (wrong sender/receiver/amount)
|
|
198
|
+
|
|
199
|
+
## Chain Support
|
|
200
|
+
|
|
201
|
+
Works on any EVM-compatible chain. Examples:
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
import { mainnet, base, arbitrum, optimism } from 'viem/chains';
|
|
205
|
+
|
|
206
|
+
// Ethereum mainnet
|
|
207
|
+
const ethVerifier = new PaymentVerifier({
|
|
208
|
+
rpcUrl: 'https://eth.llamarpc.com',
|
|
209
|
+
chain: mainnet,
|
|
210
|
+
tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' // USDC on Ethereum
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// Arbitrum
|
|
214
|
+
const arbVerifier = new PaymentVerifier({
|
|
215
|
+
rpcUrl: 'https://arb1.arbitrum.io/rpc',
|
|
216
|
+
chain: arbitrum,
|
|
217
|
+
tokenAddress: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' // USDC on Arbitrum
|
|
218
|
+
});
|
|
219
|
+
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smart-account.d.ts","sourceRoot":"","sources":["../../src/account/smart-account.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAQ,MAAM,MAAM,CAAA;AAIzH,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAE5D,qBAAa,mBAAmB;IAKxB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,SAAS,CAAC;IAPf,MAAM,EAAE,GAAG,CAAA;IACX,OAAO,EAAE,GAAG,CAAA;gBAGP,MAAM,EAAE,YAAY,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,EAC/C,YAAY,EAAE,YAAY,CAAC,SAAS,EAAE,KAAK,CAAC,EAC5C,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,gBAAgB,YAAA;IAGlC,iBAAiB,CAAC,SAAS,GAAE,MAAW;
|
|
1
|
+
{"version":3,"file":"smart-account.d.ts","sourceRoot":"","sources":["../../src/account/smart-account.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAQ,MAAM,MAAM,CAAA;AAIzH,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAE5D,qBAAa,mBAAmB;IAKxB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,SAAS,CAAC;IAPf,MAAM,EAAE,GAAG,CAAA;IACX,OAAO,EAAE,GAAG,CAAA;gBAGP,MAAM,EAAE,YAAY,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,EAC/C,YAAY,EAAE,YAAY,CAAC,SAAS,EAAE,KAAK,CAAC,EAC5C,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,gBAAgB,YAAA;IAGlC,iBAAiB,CAAC,SAAS,GAAE,MAAW;IAmC9C,UAAU,IAAI,OAAO;IAIf,YAAY,CAAC,KAAK,EAAE;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,KAAK,MAAM,EAAE,CAAA;KAAE,EAAE;IAgBzE,cAAc,CAAC,cAAc,EAAE,MAAM;CAqE9C"}
|
|
@@ -27,14 +27,20 @@ export class SmartAccountManager {
|
|
|
27
27
|
},
|
|
28
28
|
saltNonce,
|
|
29
29
|
});
|
|
30
|
+
const apiKey = this.paymaster?.getApiKey();
|
|
31
|
+
const fetchOptions = apiKey ? { headers: { 'x-api-key': apiKey } } : undefined;
|
|
30
32
|
this.client = createSmartAccountClient({
|
|
31
33
|
account: this.account,
|
|
32
34
|
chain: this.signer.chain,
|
|
33
|
-
bundlerTransport: http(this.rpcUrl),
|
|
35
|
+
bundlerTransport: http(this.rpcUrl, { fetchOptions }),
|
|
34
36
|
paymaster: this.paymaster ? this.paymaster.getClient() : undefined,
|
|
35
37
|
userOperation: {
|
|
36
38
|
estimateFeesPerGas: async () => {
|
|
37
|
-
|
|
39
|
+
const fees = await this.publicClient.estimateFeesPerGas();
|
|
40
|
+
return {
|
|
41
|
+
maxFeePerGas: (fees.maxFeePerGas * 20n) / 10n, // 2x (safety margin)
|
|
42
|
+
maxPriorityFeePerGas: (fees.maxPriorityFeePerGas * 20n) / 10n
|
|
43
|
+
};
|
|
38
44
|
}
|
|
39
45
|
}
|
|
40
46
|
}).extend(erc7579Actions());
|
|
@@ -47,8 +53,8 @@ export class SmartAccountManager {
|
|
|
47
53
|
if (!this.client)
|
|
48
54
|
throw new Error("Account not initialized");
|
|
49
55
|
// [Fee Logic] Ensure Smart Account has enough USDC for the fee
|
|
50
|
-
// We assume 0.
|
|
51
|
-
await this.ensureGasFunds(
|
|
56
|
+
// We assume 0.6 USDC is required per transaction (matching Paymaster Policy)
|
|
57
|
+
await this.ensureGasFunds(600000n);
|
|
52
58
|
const txHash = await this.client.sendTransaction({
|
|
53
59
|
calls: calls,
|
|
54
60
|
account: this.account
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smart-account.js","sourceRoot":"","sources":["../../src/account/smart-account.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAEzD,OAAO,EAAgG,IAAI,EAAE,MAAM,MAAM,CAAA;AACzH,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAI/D,MAAM,OAAO,mBAAmB;IAKhB;IACA;IACA;IACA;IAPL,MAAM,CAAK;IACX,OAAO,CAAK;IAEnB,YACY,MAA+C,EAC/C,YAA4C,EAC5C,MAAc,EACd,SAA4B;QAH5B,WAAM,GAAN,MAAM,CAAyC;QAC/C,iBAAY,GAAZ,YAAY,CAAgC;QAC5C,WAAM,GAAN,MAAM,CAAQ;QACd,cAAS,GAAT,SAAS,CAAmB;IACpC,CAAC;IAEL,KAAK,CAAC,iBAAiB,CAAC,YAAoB,EAAE;QAC1C,sCAAsC;QACtC,IAAI,CAAC,OAAO,GAAG,MAAM,kBAAkB,CAAC;YACpC,MAAM,EAAE,IAAI,CAAC,YAAY;YACzB,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;YAC7B,OAAO,EAAE,OAAO;YAChB,UAAU,EAAE;gBACR,OAAO,EAAE,4CAA4C,EAAE,iBAAiB;gBACxE,OAAO,EAAE,KAAK;aACjB;YACD,SAAS;SACZ,CAAC,CAAA;QAEF,IAAI,CAAC,MAAM,GAAG,wBAAwB,CAAC;YACnC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;YACxB,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"smart-account.js","sourceRoot":"","sources":["../../src/account/smart-account.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA;AAC1C,cAAc,0BAA0B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA;AAC1C,cAAc,0BAA0B,CAAA;AACxC,cAAc,+BAA+B,CAAA"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA;AAC1C,cAAc,0BAA0B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA;AAC1C,cAAc,0BAA0B,CAAA;AACxC,cAAc,+BAA+B,CAAA"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export declare class PaymasterManager {
|
|
2
2
|
private client;
|
|
3
|
+
private apiKey?;
|
|
3
4
|
constructor(rpcUrl?: string, apiKey?: string);
|
|
4
5
|
getClient(): any;
|
|
6
|
+
getApiKey(): string | undefined;
|
|
5
7
|
getStubPaymasterData(userOp: any): Promise<any>;
|
|
6
8
|
/**
|
|
7
9
|
* Appends a fee transfer transaction to the list of calls.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paymaster.d.ts","sourceRoot":"","sources":["../../src/paymaster/paymaster.ts"],"names":[],"mappings":"AAMA,qBAAa,gBAAgB;IACzB,OAAO,CAAC,MAAM,CAAK;
|
|
1
|
+
{"version":3,"file":"paymaster.d.ts","sourceRoot":"","sources":["../../src/paymaster/paymaster.ts"],"names":[],"mappings":"AAMA,qBAAa,gBAAgB;IACzB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,MAAM,CAAC,CAAQ;gBAEX,MAAM,GAAE,MAA6C,EAAE,MAAM,CAAC,EAAE,MAAM;IAalF,SAAS;IAIT,SAAS;IAIH,oBAAoB,CAAC,MAAM,EAAE,GAAG;IAMtC;;;;;OAKG;IACH,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,SAAS,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;CAwBxG"}
|
|
@@ -3,7 +3,9 @@ import { http, encodeFunctionData, parseAbi } from "viem";
|
|
|
3
3
|
const ERC20_ABI = parseAbi(['function transfer(address to, uint256 amount) returns (bool)']);
|
|
4
4
|
export class PaymasterManager {
|
|
5
5
|
client;
|
|
6
|
+
apiKey;
|
|
6
7
|
constructor(rpcUrl = "http://localhost:8080/v1/paymaster", apiKey) {
|
|
8
|
+
this.apiKey = apiKey;
|
|
7
9
|
const fetchOptions = apiKey ? { headers: { 'x-api-key': apiKey } } : undefined;
|
|
8
10
|
this.client = createPimlicoClient({
|
|
9
11
|
transport: http(rpcUrl, { fetchOptions }),
|
|
@@ -16,6 +18,9 @@ export class PaymasterManager {
|
|
|
16
18
|
getClient() {
|
|
17
19
|
return this.client;
|
|
18
20
|
}
|
|
21
|
+
getApiKey() {
|
|
22
|
+
return this.apiKey;
|
|
23
|
+
}
|
|
19
24
|
async getStubPaymasterData(userOp) {
|
|
20
25
|
return this.client.sponsorUserOperation({
|
|
21
26
|
userOperation: userOp
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paymaster.js","sourceRoot":"","sources":["../../src/paymaster/paymaster.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAO,MAAM,MAAM,CAAA;AAE9D,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,8DAA8D,CAAC,CAAC,CAAC;AAG7F,MAAM,OAAO,gBAAgB;IACjB,MAAM,CAAK;
|
|
1
|
+
{"version":3,"file":"paymaster.js","sourceRoot":"","sources":["../../src/paymaster/paymaster.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAO,MAAM,MAAM,CAAA;AAE9D,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,8DAA8D,CAAC,CAAC,CAAC;AAG7F,MAAM,OAAO,gBAAgB;IACjB,MAAM,CAAK;IACX,MAAM,CAAS;IAEvB,YAAY,SAAiB,oCAAoC,EAAE,MAAe;QAC9E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAE/E,IAAI,CAAC,MAAM,GAAG,mBAAmB,CAAC;YAC9B,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,YAAY,EAAE,CAAC;YACzC,UAAU,EAAE;gBACR,OAAO,EAAE,4CAA4C;gBACrD,OAAO,EAAE,KAAK;aACjB;SACJ,CAAC,CAAA;IACN,CAAC;IAED,SAAS;QACL,OAAO,IAAI,CAAC,MAAM,CAAA;IACtB,CAAC;IAED,SAAS;QACL,OAAO,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,MAAW;QAClC,OAAO,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YACpC,aAAa,EAAE,MAAM;SACxB,CAAC,CAAA;IACN,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,gBAAgB,CAAC,KAAY,EAAE,SAA+D;QACjG,yCAAyC;QACzC,MAAM,MAAM,GAAG;YACX,QAAQ,EAAE,SAAS,EAAE,QAAQ,IAAI,4CAA4C,EAAE,sBAAsB;YACrG,MAAM,EAAE,SAAS,EAAE,MAAM,IAAI,OAAO,EAAE,WAAW;YACjD,KAAK,EAAE,SAAS,EAAE,KAAK,IAAI,4CAA4C,CAAC,eAAe;SAC1F,CAAC;QAEF,IAAI,MAAM,CAAC,QAAQ,KAAK,4CAA4C,EAAE,CAAC;YACnE,OAAO,CAAC,IAAI,CAAC,uFAAuF,CAAC,CAAC;QAC1G,CAAC;QAED,MAAM,OAAO,GAAG;YACZ,EAAE,EAAE,MAAM,CAAC,KAAY;YACvB,KAAK,EAAE,EAAE;YACT,IAAI,EAAE,kBAAkB,CAAC;gBACrB,GAAG,EAAE,SAAS;gBACd,YAAY,EAAE,UAAU;gBACxB,IAAI,EAAE,CAAC,MAAM,CAAC,QAAe,EAAE,MAAM,CAAC,MAAM,CAAC;aAChD,CAAC;SACL,CAAC;QAEF,OAAO,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,CAAC;IAC/B,CAAC;CACJ"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Chain } from 'viem';
|
|
2
|
+
export interface PaymentVerificationResult {
|
|
3
|
+
isValid: boolean;
|
|
4
|
+
error?: string;
|
|
5
|
+
txHash?: `0x${string}`;
|
|
6
|
+
from?: `0x${string}`;
|
|
7
|
+
to?: `0x${string}`;
|
|
8
|
+
amount?: bigint;
|
|
9
|
+
}
|
|
10
|
+
export interface PaymentVerifierConfig {
|
|
11
|
+
rpcUrl: string;
|
|
12
|
+
chain: Chain;
|
|
13
|
+
tokenAddress?: `0x${string}`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* PaymentVerifier class for verifying ERC20 token payments on-chain.
|
|
17
|
+
* Useful for implementing pay-per-use API access patterns.
|
|
18
|
+
*/
|
|
19
|
+
export declare class PaymentVerifier {
|
|
20
|
+
private publicClient;
|
|
21
|
+
private tokenAddress;
|
|
22
|
+
/**
|
|
23
|
+
* Creates a new PaymentVerifier instance
|
|
24
|
+
* @param config Configuration object with RPC URL, chain, and optional token address
|
|
25
|
+
*/
|
|
26
|
+
constructor(config: PaymentVerifierConfig);
|
|
27
|
+
/**
|
|
28
|
+
* Verifies that a specific ERC20 transfer transaction occurred
|
|
29
|
+
* @param txHash Transaction hash to verify
|
|
30
|
+
* @param expectedFrom Expected sender address
|
|
31
|
+
* @param expectedTo Expected receiver address
|
|
32
|
+
* @param minimumAmount Minimum amount that must have been transferred (in token base units)
|
|
33
|
+
* @returns PaymentVerificationResult with verification status and details
|
|
34
|
+
*/
|
|
35
|
+
verifyPayment(txHash: `0x${string}`, expectedFrom: `0x${string}`, expectedTo: `0x${string}`, minimumAmount: bigint): Promise<PaymentVerificationResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Convenience method for verifying USDC payments
|
|
38
|
+
* @param txHash Transaction hash to verify
|
|
39
|
+
* @param expectedFrom Expected sender address
|
|
40
|
+
* @param expectedTo Expected receiver address
|
|
41
|
+
* @param minimumUSDC Minimum USDC amount in base units (1 USDC = 1000000)
|
|
42
|
+
*/
|
|
43
|
+
verifyUSDCPayment(txHash: `0x${string}`, expectedFrom: `0x${string}`, expectedTo: `0x${string}`, minimumUSDC: bigint): Promise<PaymentVerificationResult>;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=payment-verifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment-verifier.d.ts","sourceRoot":"","sources":["../../src/payment/payment-verifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+E,KAAK,EAAE,MAAM,MAAM,CAAC;AAI1G,MAAM,WAAW,yBAAyB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IACrB,EAAE,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;IACb,YAAY,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;CAChC;AAED;;;GAGG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,YAAY,CAAgB;IAEpC;;;OAGG;gBACS,MAAM,EAAE,qBAAqB;IAUzC;;;;;;;OAOG;IACG,aAAa,CACf,MAAM,EAAE,KAAK,MAAM,EAAE,EACrB,YAAY,EAAE,KAAK,MAAM,EAAE,EAC3B,UAAU,EAAE,KAAK,MAAM,EAAE,EACzB,aAAa,EAAE,MAAM,GACtB,OAAO,CAAC,yBAAyB,CAAC;IA+ErC;;;;;;OAMG;IACG,iBAAiB,CACnB,MAAM,EAAE,KAAK,MAAM,EAAE,EACrB,YAAY,EAAE,KAAK,MAAM,EAAE,EAC3B,UAAU,EAAE,KAAK,MAAM,EAAE,EACzB,WAAW,EAAE,MAAM,GACpB,OAAO,CAAC,yBAAyB,CAAC;CAGxC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { createPublicClient, http, decodeEventLog, parseAbi } from 'viem';
|
|
2
|
+
const TRANSFER_EVENT_ABI = parseAbi(['event Transfer(address indexed from, address indexed to, uint256 value)']);
|
|
3
|
+
/**
|
|
4
|
+
* PaymentVerifier class for verifying ERC20 token payments on-chain.
|
|
5
|
+
* Useful for implementing pay-per-use API access patterns.
|
|
6
|
+
*/
|
|
7
|
+
export class PaymentVerifier {
|
|
8
|
+
publicClient;
|
|
9
|
+
tokenAddress;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a new PaymentVerifier instance
|
|
12
|
+
* @param config Configuration object with RPC URL, chain, and optional token address
|
|
13
|
+
*/
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.publicClient = createPublicClient({
|
|
16
|
+
chain: config.chain,
|
|
17
|
+
transport: http(config.rpcUrl)
|
|
18
|
+
});
|
|
19
|
+
// Default to USDC on Base if not specified
|
|
20
|
+
this.tokenAddress = config.tokenAddress || '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Verifies that a specific ERC20 transfer transaction occurred
|
|
24
|
+
* @param txHash Transaction hash to verify
|
|
25
|
+
* @param expectedFrom Expected sender address
|
|
26
|
+
* @param expectedTo Expected receiver address
|
|
27
|
+
* @param minimumAmount Minimum amount that must have been transferred (in token base units)
|
|
28
|
+
* @returns PaymentVerificationResult with verification status and details
|
|
29
|
+
*/
|
|
30
|
+
async verifyPayment(txHash, expectedFrom, expectedTo, minimumAmount) {
|
|
31
|
+
try {
|
|
32
|
+
// 1. Get transaction receipt
|
|
33
|
+
const receipt = await this.publicClient.getTransactionReceipt({ hash: txHash });
|
|
34
|
+
if (!receipt) {
|
|
35
|
+
return {
|
|
36
|
+
isValid: false,
|
|
37
|
+
error: 'Transaction not found'
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (receipt.status !== 'success') {
|
|
41
|
+
return {
|
|
42
|
+
isValid: false,
|
|
43
|
+
error: 'Transaction failed',
|
|
44
|
+
txHash
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// 2. Filter logs for the specified token contract
|
|
48
|
+
const tokenLogs = receipt.logs.filter(log => log.address.toLowerCase() === this.tokenAddress.toLowerCase());
|
|
49
|
+
if (tokenLogs.length === 0) {
|
|
50
|
+
return {
|
|
51
|
+
isValid: false,
|
|
52
|
+
error: 'No transfer events found for this token',
|
|
53
|
+
txHash
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// 3. Parse Transfer events and find matching one
|
|
57
|
+
for (const log of tokenLogs) {
|
|
58
|
+
try {
|
|
59
|
+
const decoded = decodeEventLog({
|
|
60
|
+
abi: TRANSFER_EVENT_ABI,
|
|
61
|
+
data: log.data,
|
|
62
|
+
topics: log.topics
|
|
63
|
+
});
|
|
64
|
+
const { from, to, value } = decoded.args;
|
|
65
|
+
// Check if this transfer matches our criteria
|
|
66
|
+
if (from.toLowerCase() === expectedFrom.toLowerCase() &&
|
|
67
|
+
to.toLowerCase() === expectedTo.toLowerCase() &&
|
|
68
|
+
value >= minimumAmount) {
|
|
69
|
+
return {
|
|
70
|
+
isValid: true,
|
|
71
|
+
txHash,
|
|
72
|
+
from,
|
|
73
|
+
to,
|
|
74
|
+
amount: value
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (decodeError) {
|
|
79
|
+
// Skip logs that don't match Transfer event signature
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// No matching transfer found
|
|
84
|
+
return {
|
|
85
|
+
isValid: false,
|
|
86
|
+
error: 'No matching transfer found in transaction',
|
|
87
|
+
txHash
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
isValid: false,
|
|
93
|
+
error: error.message || 'Unknown error during verification'
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Convenience method for verifying USDC payments
|
|
99
|
+
* @param txHash Transaction hash to verify
|
|
100
|
+
* @param expectedFrom Expected sender address
|
|
101
|
+
* @param expectedTo Expected receiver address
|
|
102
|
+
* @param minimumUSDC Minimum USDC amount in base units (1 USDC = 1000000)
|
|
103
|
+
*/
|
|
104
|
+
async verifyUSDCPayment(txHash, expectedFrom, expectedTo, minimumUSDC) {
|
|
105
|
+
return this.verifyPayment(txHash, expectedFrom, expectedTo, minimumUSDC);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=payment-verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment-verifier.js","sourceRoot":"","sources":["../../src/payment/payment-verifier.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -31,14 +31,21 @@ export class SmartAccountManager {
|
|
|
31
31
|
saltNonce,
|
|
32
32
|
})
|
|
33
33
|
|
|
34
|
+
const apiKey = this.paymaster?.getApiKey();
|
|
35
|
+
const fetchOptions = apiKey ? { headers: { 'x-api-key': apiKey } } : undefined;
|
|
36
|
+
|
|
34
37
|
this.client = createSmartAccountClient({
|
|
35
38
|
account: this.account,
|
|
36
39
|
chain: this.signer.chain,
|
|
37
|
-
bundlerTransport: http(this.rpcUrl),
|
|
40
|
+
bundlerTransport: http(this.rpcUrl, { fetchOptions }),
|
|
38
41
|
paymaster: this.paymaster ? this.paymaster.getClient() : undefined,
|
|
39
42
|
userOperation: {
|
|
40
43
|
estimateFeesPerGas: async () => {
|
|
41
|
-
|
|
44
|
+
const fees = await this.publicClient.estimateFeesPerGas();
|
|
45
|
+
return {
|
|
46
|
+
maxFeePerGas: (fees.maxFeePerGas * 20n) / 10n, // 2x (safety margin)
|
|
47
|
+
maxPriorityFeePerGas: (fees.maxPriorityFeePerGas * 20n) / 10n
|
|
48
|
+
} as any;
|
|
42
49
|
}
|
|
43
50
|
}
|
|
44
51
|
}).extend(erc7579Actions())
|
|
@@ -54,8 +61,8 @@ export class SmartAccountManager {
|
|
|
54
61
|
if (!this.client) throw new Error("Account not initialized")
|
|
55
62
|
|
|
56
63
|
// [Fee Logic] Ensure Smart Account has enough USDC for the fee
|
|
57
|
-
// We assume 0.
|
|
58
|
-
await this.ensureGasFunds(
|
|
64
|
+
// We assume 0.6 USDC is required per transaction (matching Paymaster Policy)
|
|
65
|
+
await this.ensureGasFunds(600000n);
|
|
59
66
|
|
|
60
67
|
const txHash = await this.client.sendTransaction({
|
|
61
68
|
calls: calls,
|
package/src/index.ts
CHANGED
|
@@ -6,8 +6,10 @@ const ERC20_ABI = parseAbi(['function transfer(address to, uint256 amount) retur
|
|
|
6
6
|
|
|
7
7
|
export class PaymasterManager {
|
|
8
8
|
private client: any
|
|
9
|
+
private apiKey?: string
|
|
9
10
|
|
|
10
11
|
constructor(rpcUrl: string = "http://localhost:8080/v1/paymaster", apiKey?: string) {
|
|
12
|
+
this.apiKey = apiKey;
|
|
11
13
|
const fetchOptions = apiKey ? { headers: { 'x-api-key': apiKey } } : undefined;
|
|
12
14
|
|
|
13
15
|
this.client = createPimlicoClient({
|
|
@@ -23,6 +25,10 @@ export class PaymasterManager {
|
|
|
23
25
|
return this.client
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
getApiKey() {
|
|
29
|
+
return this.apiKey;
|
|
30
|
+
}
|
|
31
|
+
|
|
26
32
|
async getStubPaymasterData(userOp: any) {
|
|
27
33
|
return this.client.sponsorUserOperation({
|
|
28
34
|
userOperation: userOp
|