gokite-aa-sdk 1.0.10 → 1.0.12
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/dist/buy-content.d.ts +20 -0
- package/dist/buy-content.js +285 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +1 -0
- package/dist/example-token-paymaster.js +313 -71
- package/dist/gokite-aa-sdk.d.ts +6 -0
- package/dist/gokite-aa-sdk.js +33 -3
- package/dist/utils.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Buy Content Script
|
|
3
|
+
*
|
|
4
|
+
* This script demonstrates the complete x402 payment flow:
|
|
5
|
+
* 1. Request protected content (receive 402 + PaymentRequirements)
|
|
6
|
+
* 2. Sign EIP-712 transfer authorization
|
|
7
|
+
* 3. Send payment via X-Payment header
|
|
8
|
+
* 4. Receive content (service verifies & settles via facilitator)
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* npm run buy
|
|
12
|
+
*
|
|
13
|
+
* Environment variables (from .env.local):
|
|
14
|
+
* AA_WALLET - AA wallet address
|
|
15
|
+
* SESSION_ID - Session ID for this agent
|
|
16
|
+
* AGENT_PRIVATE_KEY - Agent private key (signs authorizations)
|
|
17
|
+
* SERVICE_URL - Protected service URL
|
|
18
|
+
* FACILITATOR_URL - x402 facilitator URL (for health check)
|
|
19
|
+
*/
|
|
20
|
+
import "dotenv/config";
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Buy Content Script
|
|
4
|
+
*
|
|
5
|
+
* This script demonstrates the complete x402 payment flow:
|
|
6
|
+
* 1. Request protected content (receive 402 + PaymentRequirements)
|
|
7
|
+
* 2. Sign EIP-712 transfer authorization
|
|
8
|
+
* 3. Send payment via X-Payment header
|
|
9
|
+
* 4. Receive content (service verifies & settles via facilitator)
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* npm run buy
|
|
13
|
+
*
|
|
14
|
+
* Environment variables (from .env.local):
|
|
15
|
+
* AA_WALLET - AA wallet address
|
|
16
|
+
* SESSION_ID - Session ID for this agent
|
|
17
|
+
* AGENT_PRIVATE_KEY - Agent private key (signs authorizations)
|
|
18
|
+
* SERVICE_URL - Protected service URL
|
|
19
|
+
* FACILITATOR_URL - x402 facilitator URL (for health check)
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
const ethers_1 = require("ethers");
|
|
23
|
+
require("dotenv/config");
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// Configuration
|
|
26
|
+
// =============================================================================
|
|
27
|
+
const CHAIN_ID = 2368n;
|
|
28
|
+
const RPC_URL = "https://rpc-testnet.gokite.ai";
|
|
29
|
+
// From environment
|
|
30
|
+
const AA_WALLET = process.env.AA_WALLET;
|
|
31
|
+
const SESSION_ID = process.env.SESSION_ID;
|
|
32
|
+
const AGENT_PRIVATE_KEY = process.env.AGENT_PRIVATE_KEY;
|
|
33
|
+
const SERVICE_URL = process.env.SERVICE_URL || "http://localhost:8099";
|
|
34
|
+
const FACILITATOR_URL = process.env.FACILITATOR_URL || "http://localhost:8080";
|
|
35
|
+
// Validate environment
|
|
36
|
+
if (!AA_WALLET || !SESSION_ID || !AGENT_PRIVATE_KEY) {
|
|
37
|
+
console.error("❌ Missing environment variables. Please run setup first:");
|
|
38
|
+
console.error(" npm run setup");
|
|
39
|
+
console.error("\n Required: AA_WALLET, SESSION_ID, AGENT_PRIVATE_KEY");
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
const agentSigner = new ethers_1.ethers.Wallet(AGENT_PRIVATE_KEY);
|
|
43
|
+
// =============================================================================
|
|
44
|
+
// EIP-712 Signing
|
|
45
|
+
// =============================================================================
|
|
46
|
+
const TRANSFER_AUTH_TYPES = {
|
|
47
|
+
TransferWithAuthorization: [
|
|
48
|
+
{ name: "from", type: "address" },
|
|
49
|
+
{ name: "to", type: "address" },
|
|
50
|
+
{ name: "token", type: "address" },
|
|
51
|
+
{ name: "value", type: "uint256" },
|
|
52
|
+
{ name: "validAfter", type: "uint256" },
|
|
53
|
+
{ name: "validBefore", type: "uint256" },
|
|
54
|
+
{ name: "nonce", type: "bytes32" },
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
function getEIP712Domain(aaWallet, chainId) {
|
|
58
|
+
return {
|
|
59
|
+
name: "GokiteAccount",
|
|
60
|
+
version: "1",
|
|
61
|
+
chainId: chainId,
|
|
62
|
+
verifyingContract: aaWallet,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async function signTransferAuthorization(aaWallet, chainId, auth) {
|
|
66
|
+
const domain = getEIP712Domain(aaWallet, chainId);
|
|
67
|
+
return agentSigner.signTypedData(domain, TRANSFER_AUTH_TYPES, auth);
|
|
68
|
+
}
|
|
69
|
+
// =============================================================================
|
|
70
|
+
// Payment Flow Functions
|
|
71
|
+
// =============================================================================
|
|
72
|
+
/**
|
|
73
|
+
* Step 1: Request content without payment
|
|
74
|
+
* Expected: 402 Payment Required with PaymentRequirements
|
|
75
|
+
*/
|
|
76
|
+
async function requestContent(endpoint) {
|
|
77
|
+
console.log("\n Step 1: Request Content (without payment)");
|
|
78
|
+
console.log("─".repeat(50));
|
|
79
|
+
console.log(` URL: ${SERVICE_URL}${endpoint}`);
|
|
80
|
+
const response = await fetch(`${SERVICE_URL}${endpoint}`);
|
|
81
|
+
if (response.status === 402) {
|
|
82
|
+
const data = (await response.json());
|
|
83
|
+
console.log(` Status: 402 Payment Required ✅`);
|
|
84
|
+
// Find kite-testnet payment option (we'll use gokite-aa scheme to pay)
|
|
85
|
+
const kiteOption = data.accepts?.find((req) => req.network === "kite-testnet");
|
|
86
|
+
if (kiteOption) {
|
|
87
|
+
console.log(` Payment options: ${data.accepts?.length || 0}`);
|
|
88
|
+
console.log(` Selected: ${kiteOption.network} (using gokite-aa scheme)`);
|
|
89
|
+
console.log(` Amount: ${ethers_1.ethers.formatUnits(kiteOption.maxAmountRequired, 18)} TestUSD`);
|
|
90
|
+
console.log(` Pay to: ${kiteOption.payTo}`);
|
|
91
|
+
return kiteOption;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.log(" ❌ No kite-testnet payment option available");
|
|
95
|
+
console.log(" Available networks:", data.accepts?.map((r) => r.network).join(", "));
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else if (response.ok) {
|
|
100
|
+
console.log(" ⚠️ Content returned without payment (unexpected)");
|
|
101
|
+
const content = await response.text();
|
|
102
|
+
console.log(" Content:", content.slice(0, 100));
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
console.log(` ❌ Unexpected status: ${response.status}`);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Step 2: Sign payment authorization
|
|
112
|
+
*/
|
|
113
|
+
async function signPayment(requirements) {
|
|
114
|
+
console.log("\n Step 2: Sign Payment Authorization");
|
|
115
|
+
console.log("─".repeat(50));
|
|
116
|
+
const nonce = ethers_1.ethers.hexlify((0, ethers_1.randomBytes)(32));
|
|
117
|
+
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
118
|
+
const auth = {
|
|
119
|
+
from: AA_WALLET,
|
|
120
|
+
to: requirements.payTo,
|
|
121
|
+
token: requirements.asset,
|
|
122
|
+
value: BigInt(requirements.maxAmountRequired),
|
|
123
|
+
validAfter: now - 60n,
|
|
124
|
+
validBefore: now + 3600n,
|
|
125
|
+
nonce,
|
|
126
|
+
};
|
|
127
|
+
console.log(` From: ${auth.from}`);
|
|
128
|
+
console.log(` To: ${auth.to}`);
|
|
129
|
+
console.log(` Token: ${auth.token}`);
|
|
130
|
+
console.log(` Value: ${ethers_1.ethers.formatUnits(auth.value, 18)} TestUSD`);
|
|
131
|
+
console.log(` Nonce: ${nonce.slice(0, 18)}...`);
|
|
132
|
+
const signature = await signTransferAuthorization(AA_WALLET, CHAIN_ID, auth);
|
|
133
|
+
console.log(` Signature: ${signature.slice(0, 20)}...${signature.slice(-8)}`);
|
|
134
|
+
console.log(" ✅ Authorization signed");
|
|
135
|
+
const paymentPayload = {
|
|
136
|
+
x402Version: 1,
|
|
137
|
+
scheme: "gokite-aa",
|
|
138
|
+
network: requirements.network,
|
|
139
|
+
payload: {
|
|
140
|
+
signature,
|
|
141
|
+
authorization: {
|
|
142
|
+
from: auth.from,
|
|
143
|
+
to: auth.to,
|
|
144
|
+
token: auth.token,
|
|
145
|
+
value: auth.value.toString(),
|
|
146
|
+
validAfter: auth.validAfter.toString(),
|
|
147
|
+
validBefore: auth.validBefore.toString(),
|
|
148
|
+
nonce: auth.nonce,
|
|
149
|
+
},
|
|
150
|
+
sessionId: SESSION_ID,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
return { paymentPayload, nonce };
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Step 3: Send payment and get content
|
|
157
|
+
*/
|
|
158
|
+
async function buyContent(endpoint, paymentPayload) {
|
|
159
|
+
console.log("\n Step 3: Send Payment & Get Content");
|
|
160
|
+
console.log("─".repeat(50));
|
|
161
|
+
// Encode payment payload as base64
|
|
162
|
+
const xPayment = Buffer.from(JSON.stringify(paymentPayload)).toString("base64");
|
|
163
|
+
console.log(` X-Payment header length: ${xPayment.length} chars`);
|
|
164
|
+
const response = await fetch(`${SERVICE_URL}${endpoint}`, {
|
|
165
|
+
headers: {
|
|
166
|
+
"X-Payment": xPayment,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
console.log(` Status: ${response.status}`);
|
|
170
|
+
if (response.ok) {
|
|
171
|
+
const contentType = response.headers.get("content-type");
|
|
172
|
+
let content;
|
|
173
|
+
if (contentType?.includes("application/json")) {
|
|
174
|
+
const json = await response.json();
|
|
175
|
+
content = JSON.stringify(json, null, 2);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
content = await response.text();
|
|
179
|
+
}
|
|
180
|
+
console.log(" ✅ Content received!");
|
|
181
|
+
return { success: true, content };
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
const error = await response.text();
|
|
185
|
+
console.log(" ❌ Payment failed");
|
|
186
|
+
console.log(" Error:", error);
|
|
187
|
+
return { success: false, error };
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// =============================================================================
|
|
191
|
+
// Health Checks
|
|
192
|
+
// =============================================================================
|
|
193
|
+
async function checkFacilitator() {
|
|
194
|
+
console.log("\n🏥 Facilitator Health Check");
|
|
195
|
+
console.log("─".repeat(50));
|
|
196
|
+
console.log(` URL: ${FACILITATOR_URL}`);
|
|
197
|
+
try {
|
|
198
|
+
const response = await fetch(`${FACILITATOR_URL}/health`);
|
|
199
|
+
if (response.ok) {
|
|
200
|
+
console.log(" ✅ Facilitator is healthy");
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
console.log(` ❌ Status: ${response.status}`);
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
console.log(" ❌ Connection failed:", error.message);
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async function checkService() {
|
|
212
|
+
console.log("\n🏥 Service Health Check");
|
|
213
|
+
console.log("─".repeat(50));
|
|
214
|
+
console.log(` URL: ${SERVICE_URL}`);
|
|
215
|
+
try {
|
|
216
|
+
const response = await fetch(`${SERVICE_URL}/health`);
|
|
217
|
+
if (response.ok) {
|
|
218
|
+
console.log(" ✅ Service is healthy");
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
console.log(` ❌ Status: ${response.status}`);
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
console.log(" ❌ Connection failed:", error.message);
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// =============================================================================
|
|
230
|
+
// Main Flow
|
|
231
|
+
// =============================================================================
|
|
232
|
+
async function main() {
|
|
233
|
+
const endpoint = process.argv[2] || "/protected-route";
|
|
234
|
+
console.log("═".repeat(60));
|
|
235
|
+
console.log(" x402 Gokite Payment Demo - Client");
|
|
236
|
+
console.log("═".repeat(60));
|
|
237
|
+
console.log("\n📍 Configuration");
|
|
238
|
+
console.log("─".repeat(50));
|
|
239
|
+
console.log(` AA Wallet: ${AA_WALLET}`);
|
|
240
|
+
console.log(` Session ID: ${SESSION_ID.slice(0, 18)}...`);
|
|
241
|
+
console.log(` Agent: ${agentSigner.address}`);
|
|
242
|
+
console.log(` Service: ${SERVICE_URL}`);
|
|
243
|
+
console.log(` Endpoint: ${endpoint}`);
|
|
244
|
+
// // Health checks
|
|
245
|
+
// const facilitatorOk = await checkFacilitator();
|
|
246
|
+
// const serviceOk = await checkService();
|
|
247
|
+
// if (!facilitatorOk || !serviceOk) {
|
|
248
|
+
// console.error("\n❌ Health checks failed. Please ensure services are running:");
|
|
249
|
+
// console.error(" 1. Facilitator: cargo run (port 8080)");
|
|
250
|
+
// console.error(" 2. Service: cd examples/x402-axum-example && cargo run (port 8099)");
|
|
251
|
+
// process.exit(1);
|
|
252
|
+
// }
|
|
253
|
+
// Step 1: Request content (expect 402)
|
|
254
|
+
const requirements = await requestContent(endpoint);
|
|
255
|
+
if (!requirements) {
|
|
256
|
+
console.error("\n❌ Could not get payment requirements");
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
259
|
+
// Step 2: Sign payment
|
|
260
|
+
const { paymentPayload, nonce } = await signPayment(requirements);
|
|
261
|
+
// Step 3: Send payment and get content
|
|
262
|
+
const result = await buyContent(endpoint, paymentPayload);
|
|
263
|
+
// Summary
|
|
264
|
+
console.log("\n" + "═".repeat(60));
|
|
265
|
+
console.log(" Result");
|
|
266
|
+
console.log("═".repeat(60));
|
|
267
|
+
if (result.success) {
|
|
268
|
+
console.log(" ✅ Purchase successful!");
|
|
269
|
+
console.log("\n Content:");
|
|
270
|
+
console.log(" " + "─".repeat(48));
|
|
271
|
+
console.log(result.content?.split("\n").map((l) => " " + l).join("\n"));
|
|
272
|
+
console.log(" " + "─".repeat(48));
|
|
273
|
+
console.log(`\n Payment nonce: ${nonce}`);
|
|
274
|
+
console.log(" (Nonce is now used - replay protection active)");
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
console.log(" ❌ Purchase failed");
|
|
278
|
+
console.log(` Error: ${result.error}`);
|
|
279
|
+
}
|
|
280
|
+
console.log("═".repeat(60));
|
|
281
|
+
}
|
|
282
|
+
main().catch((error) => {
|
|
283
|
+
console.error(error);
|
|
284
|
+
process.exit(1);
|
|
285
|
+
});
|
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -8,6 +8,7 @@ exports.NETWORKS = {
|
|
|
8
8
|
accountFactory: '0xAba80c4c8748c114Ba8b61cda3b0112333C3b96E',
|
|
9
9
|
accountImplementation: '0x376c32FcE28aa8496465a9E5C8a03ED8B1a7fB4D',
|
|
10
10
|
paymaster: '0x9Adcbf85D5c724611a490Ba9eDc4d38d6F39e92d',
|
|
11
|
+
settlementToken: '0x0fF5393387ad2f9f691FD6Fd28e07E3969e27e63',
|
|
11
12
|
supportedTokens: [
|
|
12
13
|
{ address: '0x0000000000000000000000000000000000000000', symbol: 'KITE', decimals: 18 },
|
|
13
14
|
{ address: '0x0fF5393387ad2f9f691FD6Fd28e07E3969e27e63', symbol: 'Test USD', decimals: 18 },
|
|
@@ -1,13 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* GokiteAccount E2E Demo with x402 Facilitator Integration
|
|
5
|
+
*
|
|
6
|
+
* This script demonstrates the complete AA wallet payment flow:
|
|
7
|
+
* 1. Setup AA wallet: addSupportedToken + setMasterBudgetRules
|
|
8
|
+
* 2. Create session with agent and spending rules
|
|
9
|
+
* 3. Agent signs EIP-712 transfer authorization
|
|
10
|
+
* 4. Verify payment via x402 facilitator
|
|
11
|
+
* 5. Settle payment via x402 facilitator (or direct UserOp execution)
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* npx tsx example-token-paymaster.ts [--settle] [--direct]
|
|
15
|
+
*
|
|
16
|
+
* Options:
|
|
17
|
+
* --settle Execute real settlement via facilitator
|
|
18
|
+
* --direct Execute direct UserOp instead of facilitator
|
|
19
|
+
*/
|
|
3
20
|
const ethers_1 = require("ethers");
|
|
4
21
|
const gokite_aa_sdk_1 = require("./gokite-aa-sdk");
|
|
5
22
|
require("dotenv/config");
|
|
23
|
+
// =============================================================================
|
|
24
|
+
// Configuration
|
|
25
|
+
// =============================================================================
|
|
6
26
|
const NETWORK = "kite_testnet";
|
|
7
27
|
const RPC_URL = "https://rpc-testnet.gokite.ai";
|
|
8
28
|
const BUNDLER_URL = "https://bundler-service.staging.gokite.ai/rpc/";
|
|
9
29
|
const SETTLEMENT_TOKEN = "0x0fF5393387ad2f9f691FD6Fd28e07E3969e27e63";
|
|
10
30
|
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
31
|
+
// x402 Facilitator configuration
|
|
32
|
+
const FACILITATOR_URL = process.env.FACILITATOR_URL || "http://localhost:8080";
|
|
33
|
+
const X402_NETWORK = "kite-testnet";
|
|
34
|
+
const CHAIN_ID = 2368;
|
|
11
35
|
const sdk = new gokite_aa_sdk_1.GokiteAASDK(NETWORK, RPC_URL, BUNDLER_URL);
|
|
12
36
|
// GokiteAccount interface (includes SessionManager functions)
|
|
13
37
|
const gokiteAccountInterface = new ethers_1.ethers.Interface([
|
|
@@ -17,6 +41,7 @@ const gokiteAccountInterface = new ethers_1.ethers.Interface([
|
|
|
17
41
|
"function setMasterBudgetRules(uint256[] timeWindows, uint160[] budgets)",
|
|
18
42
|
// Session management
|
|
19
43
|
"function createSession(bytes32 sessionId, address agent, tuple(uint256 timeWindow, uint160 budget, uint96 initialWindowStartTime, bytes32[] targetProviders)[] rules)",
|
|
44
|
+
"function setSpendingRules(bytes32 sessionId, tuple(uint256 timeWindow, uint160 budget, uint96 initialWindowStartTime, bytes32[] targetProviders)[] rules)",
|
|
20
45
|
// Transfer execution
|
|
21
46
|
"function executeTransferWithAuthorization(bytes32 sessionId, tuple(address from, address to, address token, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce) auth, bytes signature)",
|
|
22
47
|
// Batch execution
|
|
@@ -38,13 +63,9 @@ const gokiteAccountInterface = new ethers_1.ethers.Interface([
|
|
|
38
63
|
// Nonce queries
|
|
39
64
|
"function isNonceUsed(bytes32 nonce) view returns (bool)",
|
|
40
65
|
]);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
* 2. Create session with agent and spending rules
|
|
45
|
-
* 3. Agent signs EIP-712 transfer authorization
|
|
46
|
-
* 4. Execute transfer with authorization
|
|
47
|
-
*/
|
|
66
|
+
// =============================================================================
|
|
67
|
+
// Environment Setup
|
|
68
|
+
// =============================================================================
|
|
48
69
|
// Owner: controls AA wallet, signs UserOps
|
|
49
70
|
const OWNER_PRIVATE_KEY = process.env.PRIVATE_KEY;
|
|
50
71
|
// Agent: signs transfer authorizations (can be same as owner for demo)
|
|
@@ -116,11 +137,140 @@ function sessionRules() {
|
|
|
116
137
|
},
|
|
117
138
|
];
|
|
118
139
|
}
|
|
119
|
-
//
|
|
140
|
+
// =============================================================================
|
|
141
|
+
// x402 Facilitator API Functions
|
|
142
|
+
// =============================================================================
|
|
143
|
+
async function facilitatorHealthCheck() {
|
|
144
|
+
console.log("\n[x402] Health Check");
|
|
145
|
+
console.log("=".repeat(50));
|
|
146
|
+
try {
|
|
147
|
+
const response = await fetch(`${FACILITATOR_URL}/health`);
|
|
148
|
+
const data = await response.json();
|
|
149
|
+
console.log(" Response:", JSON.stringify(data, null, 2));
|
|
150
|
+
console.log(" ✅ Facilitator is healthy!");
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
console.error(" ❌ Health check failed:", error);
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function getSupportedNetworks() {
|
|
159
|
+
console.log("\n[x402] Supported Networks");
|
|
160
|
+
console.log("=".repeat(50));
|
|
161
|
+
try {
|
|
162
|
+
const response = await fetch(`${FACILITATOR_URL}/supported`);
|
|
163
|
+
const data = (await response.json());
|
|
164
|
+
console.log(" Response:", JSON.stringify(data, null, 2));
|
|
165
|
+
const kinds = data.kinds || [];
|
|
166
|
+
const hasKite = kinds.some((k) => k.network === X402_NETWORK);
|
|
167
|
+
if (hasKite) {
|
|
168
|
+
console.log(" ✅ Kite testnet is supported!");
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
console.log(" ❌ Kite testnet NOT found in supported networks");
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
console.error(" ❌ Failed to get supported networks:", error);
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function buildVerifyRequest(authorization, signature, sessionIdHex, recipient) {
|
|
182
|
+
return {
|
|
183
|
+
x402Version: 1,
|
|
184
|
+
paymentPayload: {
|
|
185
|
+
x402Version: 1,
|
|
186
|
+
scheme: "gokite-aa",
|
|
187
|
+
network: X402_NETWORK,
|
|
188
|
+
payload: {
|
|
189
|
+
signature,
|
|
190
|
+
authorization,
|
|
191
|
+
sessionId: sessionIdHex,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
paymentRequirements: {
|
|
195
|
+
scheme: "gokite-aa",
|
|
196
|
+
network: X402_NETWORK,
|
|
197
|
+
maxAmountRequired: authorization.value,
|
|
198
|
+
resource: "https://example.com/api",
|
|
199
|
+
description: "Test payment via AA wallet",
|
|
200
|
+
mimeType: "application/json",
|
|
201
|
+
payTo: recipient,
|
|
202
|
+
maxTimeoutSeconds: 30,
|
|
203
|
+
asset: authorization.token,
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
async function verifyPayment(request) {
|
|
208
|
+
console.log("\n[x402] Verify Payment");
|
|
209
|
+
console.log("=".repeat(50));
|
|
210
|
+
console.log(" Request:", JSON.stringify(request, null, 2));
|
|
211
|
+
try {
|
|
212
|
+
const response = await fetch(`${FACILITATOR_URL}/verify`, {
|
|
213
|
+
method: "POST",
|
|
214
|
+
headers: { "Content-Type": "application/json" },
|
|
215
|
+
body: JSON.stringify(request),
|
|
216
|
+
});
|
|
217
|
+
const data = (await response.json());
|
|
218
|
+
console.log("\n Response:", JSON.stringify(data, null, 2));
|
|
219
|
+
if (data.isValid) {
|
|
220
|
+
console.log("\n ✅ Verification PASSED!");
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
console.log("\n ❌ Verification FAILED:", data.invalidReason);
|
|
224
|
+
}
|
|
225
|
+
return data;
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
console.error(" ❌ Verify request failed:", error);
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function settlePayment(request) {
|
|
233
|
+
console.log("\n[x402] Settle Payment");
|
|
234
|
+
console.log("=".repeat(50));
|
|
235
|
+
console.log(" Request:", JSON.stringify(request, null, 2));
|
|
236
|
+
try {
|
|
237
|
+
const response = await fetch(`${FACILITATOR_URL}/settle`, {
|
|
238
|
+
method: "POST",
|
|
239
|
+
headers: { "Content-Type": "application/json" },
|
|
240
|
+
body: JSON.stringify(request),
|
|
241
|
+
});
|
|
242
|
+
const data = (await response.json());
|
|
243
|
+
console.log("\n Response:", JSON.stringify(data, null, 2));
|
|
244
|
+
if (data.success) {
|
|
245
|
+
console.log("\n ✅ Settlement SUCCESSFUL!");
|
|
246
|
+
if (data.transaction) {
|
|
247
|
+
console.log(" Transaction Hash:", data.transaction);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
console.log("\n ❌ Settlement FAILED:", data.errorReason);
|
|
252
|
+
}
|
|
253
|
+
return data;
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
console.error(" ❌ Settle request failed:", error);
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// =============================================================================
|
|
261
|
+
// Query Functions
|
|
262
|
+
// =============================================================================
|
|
120
263
|
async function queryWalletStatus(aaWallet, provider) {
|
|
121
|
-
const contract = new ethers_1.ethers.Contract(aaWallet, gokiteAccountInterface, provider);
|
|
122
264
|
console.log("\n[Query] AA Wallet Status");
|
|
123
265
|
console.log("=".repeat(50));
|
|
266
|
+
// Check if wallet is deployed first
|
|
267
|
+
const code = await provider.getCode(aaWallet);
|
|
268
|
+
if (code === "0x") {
|
|
269
|
+
console.log(` AA Wallet ${aaWallet} is not deployed yet (counterfactual address)`);
|
|
270
|
+
console.log(` Wallet will be deployed on first UserOp execution`);
|
|
271
|
+
return { isDeployed: false, isSupported: false, balance: 0n };
|
|
272
|
+
}
|
|
273
|
+
const contract = new ethers_1.ethers.Contract(aaWallet, gokiteAccountInterface, provider);
|
|
124
274
|
// 1. Check if token is supported
|
|
125
275
|
const isSupported = await contract.isTokenSupported(SETTLEMENT_TOKEN);
|
|
126
276
|
console.log(` Token ${SETTLEMENT_TOKEN} supported: ${isSupported}`);
|
|
@@ -138,22 +288,22 @@ async function queryWalletStatus(aaWallet, provider) {
|
|
|
138
288
|
const windowType = timeWindow === 0n ? "per-tx" : `${Number(timeWindow) / 86400} day(s)`;
|
|
139
289
|
console.log(` Rule ${i}: ${windowType}, budget: ${budget}, used: ${used}`);
|
|
140
290
|
}
|
|
141
|
-
return { isSupported, balance };
|
|
291
|
+
return { isDeployed: true, isSupported, balance };
|
|
142
292
|
}
|
|
143
|
-
async function querySessionStatus(aaWallet,
|
|
293
|
+
async function querySessionStatus(aaWallet, sessionIdHex, provider) {
|
|
144
294
|
const contract = new ethers_1.ethers.Contract(aaWallet, gokiteAccountInterface, provider);
|
|
145
295
|
console.log("\n[Query] Session Status");
|
|
146
296
|
console.log("=".repeat(50));
|
|
147
297
|
// 1. Check if session exists
|
|
148
|
-
const exists = await contract.sessionExists(
|
|
149
|
-
console.log(` Session ${
|
|
298
|
+
const exists = await contract.sessionExists(sessionIdHex);
|
|
299
|
+
console.log(` Session ${sessionIdHex.slice(0, 18)}... exists: ${exists}`);
|
|
150
300
|
if (!exists)
|
|
151
301
|
return { exists };
|
|
152
302
|
// 2. Get session agent
|
|
153
|
-
const agent = await contract.getSessionAgent(
|
|
303
|
+
const agent = await contract.getSessionAgent(sessionIdHex);
|
|
154
304
|
console.log(` Session agent: ${agent}`);
|
|
155
305
|
// 3. Get spending rules
|
|
156
|
-
const spendingRules = await contract.getSpendingRules(
|
|
306
|
+
const spendingRules = await contract.getSpendingRules(sessionIdHex);
|
|
157
307
|
console.log(` Spending rules count: ${spendingRules.length}`);
|
|
158
308
|
for (let i = 0; i < spendingRules.length; i++) {
|
|
159
309
|
const rule = spendingRules[i];
|
|
@@ -163,10 +313,6 @@ async function querySessionStatus(aaWallet, sessionId, provider) {
|
|
|
163
313
|
const windowType = timeWindow === 0n ? "per-tx" : `${Number(timeWindow) / 86400} day(s)`;
|
|
164
314
|
console.log(` Rule ${i}: ${windowType}, budget: ${budget}, used: ${used}`);
|
|
165
315
|
}
|
|
166
|
-
// 4. Check if a specific amount would pass spending rules
|
|
167
|
-
const testAmount = ethers_1.ethers.parseUnits("5", 18);
|
|
168
|
-
const wouldPass = await contract.checkSpendingRules(sessionId, testAmount, ethers_1.ethers.ZeroHash);
|
|
169
|
-
console.log(` Would ${ethers_1.ethers.formatUnits(testAmount, 18)} pass spending rules: ${wouldPass}`);
|
|
170
316
|
return { exists, agent, spendingRules };
|
|
171
317
|
}
|
|
172
318
|
async function checkNonceStatus(aaWallet, nonce, provider) {
|
|
@@ -175,29 +321,49 @@ async function checkNonceStatus(aaWallet, nonce, provider) {
|
|
|
175
321
|
console.log(` Nonce ${nonce.slice(0, 18)}... used: ${isUsed}`);
|
|
176
322
|
return isUsed;
|
|
177
323
|
}
|
|
324
|
+
// =============================================================================
|
|
325
|
+
// Main Flow
|
|
326
|
+
// =============================================================================
|
|
178
327
|
async function main() {
|
|
328
|
+
const args = process.argv.slice(2);
|
|
329
|
+
const shouldSettle = args.includes("--settle");
|
|
330
|
+
const useDirect = args.includes("--direct");
|
|
331
|
+
console.log("=".repeat(60));
|
|
332
|
+
console.log("GokiteAccount E2E Demo with x402 Facilitator");
|
|
333
|
+
console.log("=".repeat(60));
|
|
179
334
|
const aaWallet = sdk.getAccountAddress(ownerSigner.address);
|
|
180
335
|
const provider = new ethers_1.ethers.JsonRpcProvider(RPC_URL);
|
|
181
336
|
const chainId = (await provider.getNetwork()).chainId;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
console.log("
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
[]
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
337
|
+
console.log("\nConfiguration:");
|
|
338
|
+
console.log(" Facilitator URL:", FACILITATOR_URL);
|
|
339
|
+
console.log(" Network:", X402_NETWORK);
|
|
340
|
+
console.log(" Chain ID:", CHAIN_ID);
|
|
341
|
+
console.log(" AA Wallet:", aaWallet);
|
|
342
|
+
console.log(" Owner:", ownerSigner.address);
|
|
343
|
+
console.log(" Agent:", agentSigner.address);
|
|
344
|
+
console.log(" Token:", SETTLEMENT_TOKEN);
|
|
345
|
+
console.log(" Mode:", useDirect ? "Direct UserOp" : "x402 Facilitator");
|
|
346
|
+
// ============ Query Wallet Status ============
|
|
347
|
+
const walletStatus = await queryWalletStatus(aaWallet, provider);
|
|
348
|
+
// ============ Step 1: Setup AA Wallet (only if not deployed) ============
|
|
349
|
+
if (!walletStatus.isDeployed) {
|
|
350
|
+
console.log("\n[Step 1] Setting up AA wallet...");
|
|
351
|
+
const masterBudgetData = gokiteAccountInterface.encodeFunctionData("setMasterBudgetRules", [
|
|
352
|
+
[BigInt(SECONDS_PER_DAY), 0n],
|
|
353
|
+
[ethers_1.ethers.parseUnits("1000", 18), ethers_1.ethers.parseUnits("100", 18)], // 1000 USD/day, 100 USD/tx
|
|
354
|
+
]);
|
|
355
|
+
const setupBatchData = gokiteAccountInterface.encodeFunctionData("executeBatch", [
|
|
356
|
+
[aaWallet],
|
|
357
|
+
[],
|
|
358
|
+
[masterBudgetData],
|
|
359
|
+
]);
|
|
360
|
+
const setupTx = await sendWithTokenPayment(aaWallet, setupBatchData);
|
|
361
|
+
console.log(` Setup (addSupportedToken + setMasterBudgetRules) tx: ${setupTx}`);
|
|
362
|
+
await new Promise((r) => setTimeout(r, 5000));
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
console.log("\n[Step 1] AA wallet already deployed, skipping setup");
|
|
366
|
+
}
|
|
201
367
|
// ============ Step 2: Create Session ============
|
|
202
368
|
console.log("\n[Step 2] Creating session...");
|
|
203
369
|
const createSessionData = gokiteAccountInterface.encodeFunctionData("createSession", [
|
|
@@ -211,41 +377,117 @@ async function main() {
|
|
|
211
377
|
await new Promise((r) => setTimeout(r, 5000));
|
|
212
378
|
// Query session status after creation
|
|
213
379
|
await querySessionStatus(aaWallet, sessionId, provider);
|
|
214
|
-
// ============ Step
|
|
215
|
-
console.log("\n[Step
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
380
|
+
// ============ Step 2b: Update Spending Rules (setSpendingRules example) ============
|
|
381
|
+
console.log("\n[Step 2b] Updating session spending rules...");
|
|
382
|
+
// Define new spending rules to replace existing ones
|
|
383
|
+
const newSpendingRules = [
|
|
384
|
+
{
|
|
385
|
+
timeWindow: BigInt(SECONDS_PER_DAY),
|
|
386
|
+
budget: ethers_1.ethers.parseUnits("200", 18),
|
|
387
|
+
initialWindowStartTime: currentDayStart(),
|
|
388
|
+
targetProviders: [],
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
timeWindow: 0n,
|
|
392
|
+
budget: ethers_1.ethers.parseUnits("20", 18),
|
|
393
|
+
initialWindowStartTime: 0n,
|
|
394
|
+
targetProviders: [],
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
timeWindow: BigInt(SECONDS_PER_DAY * 7),
|
|
398
|
+
budget: ethers_1.ethers.parseUnits("500", 18),
|
|
399
|
+
initialWindowStartTime: currentDayStart(),
|
|
400
|
+
targetProviders: [],
|
|
401
|
+
},
|
|
402
|
+
];
|
|
403
|
+
const setSpendingRulesData = gokiteAccountInterface.encodeFunctionData("setSpendingRules", [
|
|
404
|
+
sessionId,
|
|
405
|
+
newSpendingRules,
|
|
406
|
+
]);
|
|
407
|
+
const setSpendingRulesTx = await sendWithTokenPayment(aaWallet, setSpendingRulesData);
|
|
408
|
+
console.log(` setSpendingRules tx: ${setSpendingRulesTx}`);
|
|
237
409
|
await new Promise((r) => setTimeout(r, 5000));
|
|
238
|
-
//
|
|
239
|
-
console.log("\n[Post-Transfer] Checking status...");
|
|
240
|
-
// Check nonce is now used (replay protection)
|
|
241
|
-
await checkNonceStatus(aaWallet, nonce, provider);
|
|
242
|
-
// Query updated session status (usage should be updated)
|
|
410
|
+
// Query session status after updating spending rules
|
|
243
411
|
await querySessionStatus(aaWallet, sessionId, provider);
|
|
244
|
-
//
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
412
|
+
// // ============ Step 3: Sign Transfer Authorization ============
|
|
413
|
+
// console.log("\n[Step 3] Agent signing transfer authorization...");
|
|
414
|
+
// const recipient = ownerSigner.address; // send to self for demo
|
|
415
|
+
// const transferAmount = ethers.parseUnits("1", 18); // 1 token
|
|
416
|
+
// const nonce = ethers.hexlify(randomBytes(32));
|
|
417
|
+
// const now = BigInt(Math.floor(Date.now() / 1000));
|
|
418
|
+
// const auth = {
|
|
419
|
+
// from: aaWallet,
|
|
420
|
+
// to: recipient,
|
|
421
|
+
// token: SETTLEMENT_TOKEN,
|
|
422
|
+
// value: transferAmount,
|
|
423
|
+
// validAfter: now - 60n, // valid from 1 minute ago
|
|
424
|
+
// validBefore: now + 3600n, // valid for 1 hour
|
|
425
|
+
// nonce: nonce,
|
|
426
|
+
// };
|
|
427
|
+
// const signature = await signTransferAuthorization(aaWallet, chainId, auth);
|
|
428
|
+
// console.log(` Authorization nonce: ${nonce}`);
|
|
429
|
+
// console.log(` Signature: ${signature.slice(0, 42)}...`);
|
|
430
|
+
// // ============ Step 4: Execute Transfer ============
|
|
431
|
+
// if (useDirect) {
|
|
432
|
+
// // Direct UserOp execution
|
|
433
|
+
// console.log("\n[Step 4] Executing transfer via direct UserOp...");
|
|
434
|
+
// const executeTransferData = gokiteAccountInterface.encodeFunctionData(
|
|
435
|
+
// "executeTransferWithAuthorization",
|
|
436
|
+
// [sessionId, auth, signature]
|
|
437
|
+
// );
|
|
438
|
+
// const executeTx = await sendWithTokenPayment(aaWallet, executeTransferData);
|
|
439
|
+
// console.log(` executeTransferWithAuthorization tx: ${executeTx}`);
|
|
440
|
+
// } else {
|
|
441
|
+
// // x402 Facilitator flow
|
|
442
|
+
// console.log("\n[Step 4] Verifying via x402 facilitator...");
|
|
443
|
+
// // Check facilitator health
|
|
444
|
+
// const healthy = await facilitatorHealthCheck();
|
|
445
|
+
// if (!healthy) {
|
|
446
|
+
// console.error("\n❌ Facilitator not available, aborting");
|
|
447
|
+
// process.exit(1);
|
|
448
|
+
// }
|
|
449
|
+
// // Check supported networks
|
|
450
|
+
// await getSupportedNetworks();
|
|
451
|
+
// // Build x402 request
|
|
452
|
+
// const x402Auth: Authorization = {
|
|
453
|
+
// from: aaWallet,
|
|
454
|
+
// to: recipient,
|
|
455
|
+
// token: SETTLEMENT_TOKEN,
|
|
456
|
+
// value: transferAmount.toString(),
|
|
457
|
+
// validAfter: auth.validAfter.toString(),
|
|
458
|
+
// validBefore: auth.validBefore.toString(),
|
|
459
|
+
// nonce: nonce,
|
|
460
|
+
// };
|
|
461
|
+
// const verifyRequest = buildVerifyRequest(x402Auth, signature, sessionId, recipient);
|
|
462
|
+
// // Verify payment
|
|
463
|
+
// const verifyResult = await verifyPayment(verifyRequest);
|
|
464
|
+
// if (!verifyResult?.isValid) {
|
|
465
|
+
// console.error("\n❌ Verification failed, skipping settle");
|
|
466
|
+
// process.exit(1);
|
|
467
|
+
// }
|
|
468
|
+
// // Settle payment (optional)
|
|
469
|
+
// if (shouldSettle) {
|
|
470
|
+
// console.log("\n⚠️ Proceeding with REAL settlement transaction...");
|
|
471
|
+
// const settleResult = await settlePayment(verifyRequest);
|
|
472
|
+
// if (settleResult?.success && settleResult.transaction) {
|
|
473
|
+
// console.log(` Settlement tx: ${settleResult.transaction}`);
|
|
474
|
+
// }
|
|
475
|
+
// } else {
|
|
476
|
+
// console.log("\n💡 Skipping settle (use --settle flag to execute real transaction)");
|
|
477
|
+
// }
|
|
478
|
+
// }
|
|
479
|
+
// await new Promise((r) => setTimeout(r, 5000));
|
|
480
|
+
// // ============ Post-Transfer Queries ============
|
|
481
|
+
// console.log("\n[Post-Transfer] Checking status...");
|
|
482
|
+
// // Check nonce is now used (replay protection)
|
|
483
|
+
// await checkNonceStatus(aaWallet, nonce, provider);
|
|
484
|
+
// // Query updated session status (usage should be updated)
|
|
485
|
+
// await querySessionStatus(aaWallet, sessionId, provider);
|
|
486
|
+
// // Query updated wallet status
|
|
487
|
+
// await queryWalletStatus(aaWallet, provider);
|
|
488
|
+
// console.log("\n" + "=".repeat(60));
|
|
489
|
+
// console.log("E2E Demo completed successfully!");
|
|
490
|
+
// console.log("=".repeat(60));
|
|
249
491
|
}
|
|
250
492
|
main().catch((error) => {
|
|
251
493
|
console.error(error);
|
package/dist/gokite-aa-sdk.d.ts
CHANGED
|
@@ -35,8 +35,14 @@ export declare class GokiteAASDK {
|
|
|
35
35
|
* Build call data for batch transactions
|
|
36
36
|
*/
|
|
37
37
|
buildBatchCallData(request: BatchUserOperationRequest): string;
|
|
38
|
+
/**
|
|
39
|
+
* Prepend addSupportedToken call to request for first transaction (wallet deployment)
|
|
40
|
+
* Uses settlement token from config (supportedTokens[1])
|
|
41
|
+
*/
|
|
42
|
+
private prependAddSupportedToken;
|
|
38
43
|
/**
|
|
39
44
|
* Create user operation
|
|
45
|
+
* If wallet is not deployed, automatically batch addSupportedToken into the first transaction
|
|
40
46
|
*/
|
|
41
47
|
createUserOperation(owner: string, request: UserOperationRequest | BatchUserOperationRequest, salt?: bigint, paymasterAddress?: string, tokenAddress?: string): Promise<Partial<UserOperation>>;
|
|
42
48
|
/**
|
package/dist/gokite-aa-sdk.js
CHANGED
|
@@ -251,16 +251,46 @@ class GokiteAASDK {
|
|
|
251
251
|
const values = request.values || new Array(request.targets.length).fill(0n);
|
|
252
252
|
return (0, utils_1.encodeFunctionCall)(['function executeBatch(address[],uint256[],bytes[])'], 'executeBatch', [request.targets, values, request.callDatas]);
|
|
253
253
|
}
|
|
254
|
+
/**
|
|
255
|
+
* Prepend addSupportedToken call to request for first transaction (wallet deployment)
|
|
256
|
+
* Uses settlement token from config (supportedTokens[1])
|
|
257
|
+
*/
|
|
258
|
+
prependAddSupportedToken(request, accountAddress) {
|
|
259
|
+
const settlementToken = this.config.settlementToken;
|
|
260
|
+
const addTokenCallData = (0, utils_1.encodeFunctionCall)(['function addSupportedToken(address)'], 'addSupportedToken', [settlementToken]);
|
|
261
|
+
if ('target' in request) {
|
|
262
|
+
// Convert single request to batch with addSupportedToken prepended
|
|
263
|
+
return {
|
|
264
|
+
targets: [accountAddress, request.target],
|
|
265
|
+
values: [BigInt(0), request.value || BigInt(0)],
|
|
266
|
+
callDatas: [addTokenCallData, request.callData]
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
// Prepend to existing batch
|
|
271
|
+
return {
|
|
272
|
+
targets: [accountAddress, ...request.targets],
|
|
273
|
+
values: [BigInt(0), ...(request.values || new Array(request.targets.length).fill(BigInt(0)))],
|
|
274
|
+
callDatas: [addTokenCallData, ...request.callDatas]
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}
|
|
254
278
|
/**
|
|
255
279
|
* Create user operation
|
|
280
|
+
* If wallet is not deployed, automatically batch addSupportedToken into the first transaction
|
|
256
281
|
*/
|
|
257
282
|
async createUserOperation(owner, request, salt, paymasterAddress, tokenAddress) {
|
|
258
283
|
const actualSalt = salt || (0, utils_1.generateSalt)();
|
|
259
284
|
const accountAddress = this.getAccountAddress(owner, actualSalt);
|
|
260
285
|
const isDeployed = await this.isAccountDeloyed(accountAddress);
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
286
|
+
// If wallet not deployed, batch addSupportedToken into first transaction
|
|
287
|
+
let finalRequest = request;
|
|
288
|
+
if (!isDeployed) {
|
|
289
|
+
finalRequest = this.prependAddSupportedToken(request, accountAddress);
|
|
290
|
+
}
|
|
291
|
+
const callData = 'targets' in finalRequest
|
|
292
|
+
? this.buildBatchCallData(finalRequest)
|
|
293
|
+
: this.buildCallData(finalRequest);
|
|
264
294
|
// Gas settings (matching Go implementation)
|
|
265
295
|
const callGasLimit = BigInt(300000);
|
|
266
296
|
const verificationGasLimit = BigInt(300000);
|
package/dist/utils.js
CHANGED
|
@@ -130,7 +130,7 @@ function serializeUserOperation(userOp) {
|
|
|
130
130
|
exports.serializeUserOperation = serializeUserOperation;
|
|
131
131
|
// default salt is 0
|
|
132
132
|
function generateSalt() {
|
|
133
|
-
return BigInt(
|
|
133
|
+
return BigInt(1);
|
|
134
134
|
}
|
|
135
135
|
exports.generateSalt = generateSalt;
|
|
136
136
|
/**
|