gokite-aa-sdk 1.0.2 → 1.0.3

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/example.js CHANGED
@@ -1,16 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.example = exports.handleAAError = exports.CheckTokenBalance = exports.WithdrawFunds = exports.ViewSpendingRules = exports.ConfigureSpendingRules = exports.DeployClientAgentVaultProxy = exports.basicExample = exports.clientAgentVaultIntegrationTests = void 0;
3
+ exports.parseContractCreatedEvent = exports.getTransparentProxyBytecode = exports.handleAAError = exports.initializeSDK = exports.registerService = exports.checkTokenBalance = exports.withdrawFunds = exports.viewSpendingRules = exports.configureSpendingRules = exports.deployKitePass = exports.transferERC20 = void 0;
4
4
  const gokite_aa_sdk_1 = require("./gokite-aa-sdk");
5
5
  const types_1 = require("./types");
6
6
  const ethers_1 = require("ethers");
7
7
  require("dotenv/config");
8
+ /**
9
+ * Sections:
10
+ * 1. General Use - ERC20 Token Transfer (通用功能 - ERC20代币转账)
11
+ * 2. KitePass Related - ClientAgentVault Operations (KitePass相关 - 客户端代理金库操作)
12
+ * 3. Subnet Related - Subnet Management (子网相关 - 子网管理)
13
+ * 4. Service Related - Service Registry Operations (服务相关 - 服务注册表操作)
14
+ */
8
15
  // Contract addresses on kite_testnet
9
16
  const ADDRESSES = {
10
17
  SETTLEMENT_TOKEN: '0x0fF5393387ad2f9f691FD6Fd28e07E3969e27e63',
11
18
  SETTLEMENT_CONTRACT: '0x8d9FaD78d5Ce247aA01C140798B9558fd64a63E3',
12
- CLIENT_AGENT_VAULT_IMPL: '0xB5AAFCC6DD4DFc2B80fb8BCcf406E1a2Fd559e23'
19
+ CLIENT_AGENT_VAULT_IMPL: '0xB5AAFCC6DD4DFc2B80fb8BCcf406E1a2Fd559e23',
20
+ SERVICE_REGISTRY: '0xF727EDE22C9e338a7d1d57B930dcEBbC6a66c008'
13
21
  };
22
+ // SDK initialization - 初始化SDK
23
+ function initializeSDK() {
24
+ return new gokite_aa_sdk_1.GokiteAASDK('kite_testnet', 'https://rpc-testnet.gokite.ai', 'https://bundler-service.staging.gokite.ai/rpc/');
25
+ }
26
+ exports.initializeSDK = initializeSDK;
14
27
  function handleAAError(error) {
15
28
  if (error instanceof types_1.AASDKError) {
16
29
  return {
@@ -19,7 +32,6 @@ function handleAAError(error) {
19
32
  details: error.details
20
33
  };
21
34
  }
22
- // Fallback for other errors
23
35
  return {
24
36
  type: 'UNKNOWN_ERROR',
25
37
  message: error.message || 'An unknown error occurred',
@@ -27,142 +39,146 @@ function handleAAError(error) {
27
39
  };
28
40
  }
29
41
  exports.handleAAError = handleAAError;
42
+ // =============================================================================
43
+ // 1. GENERAL USE - ERC20 Token Transfer
44
+ // 通用功能 - ERC20代币转账
45
+ // =============================================================================
30
46
  /**
31
- * Get TransparentUpgradeableProxy bytecode
32
- */
33
- function getTransparentProxyBytecode() {
34
- // This is the bytecode for TransparentUpgradeableProxy
35
- return '0x60a0604052610b278038038061001481610293565b928339810160608282031261028e5761002c826102b8565b610038602084016102b8565b604084015190936001600160401b03821161028e570182601f8201121561028e5780519061006d610068836102cc565b610293565b938285526020838301011161028e5760005b828110610279575050602060009184010152803b15610258577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0383169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a281511561023f5760008083602061013595519101845af43d15610237573d91610125610068846102cc565b9283523d6000602085013e6102e7565b505b604051906104918083016001600160401b0381118482101761022157602092849261067684396001600160a01b031681520301906000f080156102155760018060a01b031680608052600080516020610b07833981519152547f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6040805160018060a01b0384168152846020820152a181156101ff576001600160a01b03191617600080516020610b078339815191525560405161032d908161034982396080518160070152f35b633173bdd160e11b600052600060045260246000fd5b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b6060916102e7565b505034156101375763b398979f60e01b60005260046000fd5b634c9c8ce360e01b60009081526001600160a01b0391909116600452602490fd5b8060208092840101518282880101520161007f565b600080fd5b6040519190601f01601f191682016001600160401b0381118382101761022157604052565b51906001600160a01b038216820361028e57565b6001600160401b03811161022157601f01601f191660200190565b9061030d57508051156102fc57805190602001fd5b630a12f52160e11b60005260046000fd5b8151158061033f575b61031e575090565b639996b31560e01b60009081526001600160a01b0391909116600452602490fd5b50803b1561031656fe6080604052337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610069576000356001600160e01b03191663278f794360e11b1461005f576334ad5dbb60e21b60005260046000fd5b610067610113565b005b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5460009081906001600160a01b0316368280378136915af43d6000803e156100b1573d6000f35b3d6000fd5b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f1916820167ffffffffffffffff8111838210176100f257604052565b6100b6565b67ffffffffffffffff81116100f257601f01601f191660200190565b3660041161019d57604036600319011261019d576004356001600160a01b0381169081900361019d576024359067ffffffffffffffff821161019d573660238301121561019d5781600401359061017161016c836100f7565b6100cc565b91808352366024828601011161019d57602081600092602461019b970183870137840101526101a2565b565b600080fd5b90813b15610239577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a280511561021f5761021c9161025b565b50565b50503461022857565b63b398979f60e01b60005260046000fd5b50634c9c8ce360e01b60009081526001600160a01b0391909116600452602490fd5b60008061028f93602081519101845af43d15610292573d9161027f61016c846100f7565b9283523d6000602085013e610296565b90565b6060915b906102bc57508051156102ab57805190602001fd5b630a12f52160e11b60005260046000fd5b815115806102ee575b6102cd575090565b639996b31560e01b60009081526001600160a01b0391909116600452602490fd5b50803b156102c556fea2646970667358221220597147005a6fe654561cbab25a93153cc233180473a65a90bd427f0c1f41018764736f6c634300081c003360803460bc57601f61049138819003918201601f19168301916001600160401b0383118484101760c15780849260209460405283398101031260bc57516001600160a01b0381169081900360bc57801560a657600080546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36103b990816100d88239f35b631e4fbdf760e01b600052600060045260246000fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe6080604052600436101561001257600080fd5b6000803560e01c8063715018a6146102875780638da5cb5b146102605780639623609d1461012f578063ad3cb1cc146100e25763f2fde38b1461005457600080fd5b346100df5760203660031901126100df576004356001600160a01b038116908190036100dd5761008261035a565b80156100c95781546001600160a01b03198116821783556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b631e4fbdf760e01b82526004829052602482fd5b505b80fd5b50346100df57806003193601126100df575061012b6040516101056040826102e1565b60058152640352e302e360dc1b6020820152604051918291602083526020830190610319565b0390f35b5060603660031901126100df576004356001600160a01b038116908190036100dd576024356001600160a01b038116908190036102405760443567ffffffffffffffff811161025c573660238201121561025c57806004013567ffffffffffffffff8111610248576040518593929091906101b4601f8301601f1916602001846102e1565b81835236602483830101116102445781859260246020930183860137830101526101dc61035a565b833b156102405761021293839260405180968194829363278f794360e11b84526004840152604060248401526044830190610319565b039134905af18015610233576102255780f35b61022e916102e1565b388180f35b50604051903d90823e3d90fd5b8280fd5b8480fd5b634e487b7160e01b85526041600452602485fd5b8380fd5b50346100df57806003193601126100df57546040516001600160a01b039091168152602090f35b50346100df57806003193601126100df576102a061035a565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b90601f8019910116810190811067ffffffffffffffff82111761030357604052565b634e487b7160e01b600052604160045260246000fd5b919082519283825260005b848110610345575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201610324565b6000546001600160a01b0316330361036e57565b63118cdaa760e01b6000523360045260246000fdfea26469706673582212207bc32ec723f6be34b228b59aef2ef61b4e6a8eb5bc67fcdd495248566e3b6e0c64736f6c634300081c0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103';
36
- }
37
- /**
38
- * ClientAgentVault Integration Tests
47
+ * Transfer ERC20 tokens from AA wallet to another address
48
+ * 从AA钱包转账ERC20代币到其他地址
39
49
  *
40
- * these tests show how to use the AA wallet to:
41
- * 1. deploy the ClientAgentVault proxy contract (via performCreate)
42
- * 2. configure spending rules (Spending Rules)
43
- * 3. view spending rules (read-only)
44
- * 4. withdraw funds (withdrawFunds)
45
- * 5. check token balance (read-only)
46
- *
47
- * how to use:
48
- * - modify the contract addresses and parameters as needed
50
+ * @param eoa - User's EOA address (from Privy)
51
+ * @param to - Recipient address
52
+ * @param amount - Amount to transfer
53
+ * @param tokenAddress - Token contract address
54
+ * @param tokenDecimals - Token decimals (usually 18)
55
+ * @param signFunction - Signing function from Privy
49
56
  */
50
- async function clientAgentVaultIntegrationTests() {
51
- console.log('\n=== ClientAgentVault Integration Tests ===');
52
- // Initialize SDK
53
- const sdk = new gokite_aa_sdk_1.GokiteAASDK('kite_testnet', 'https://rpc-testnet.gokite.ai', 'https://bundler-service.staging.gokite.ai/rpc/');
54
- // user's EOA address and AA wallet address
55
- const eoa = '0x4A50DCA63d541372ad36E5A36F1D542d51164F19';
56
- const aa = sdk.getAccountAddress(eoa);
57
- console.log('AA Wallet Address:', aa);
58
- // Sign function, replace with particle or privy sdk
59
- const signFunction = async (userOpHash) => {
60
- const signer_pk = process.env.PRIVATE_KEY;
61
- const signer = new ethers_1.ethers.Wallet(signer_pk);
62
- return signer.signMessage(ethers_1.ethers.getBytes(userOpHash));
63
- };
64
- // 1. Deploy ClientAgentVault Proxy via performCreate
65
- console.log('\n--- Test 1: Deploy ClientAgentVault Proxy ---');
66
- const deployedProxyAddress = await DeployClientAgentVaultProxy(sdk, eoa, aa, signFunction);
67
- if (!deployedProxyAddress) {
68
- console.log('❌ Failed to deploy proxy, cannot continue with other tests');
69
- return;
57
+ async function transferERC20(eoa, to, amount, tokenAddress, tokenDecimals = 18, signFunction) {
58
+ const sdk = initializeSDK();
59
+ try {
60
+ const transferRequest = {
61
+ target: tokenAddress,
62
+ value: 0n,
63
+ callData: ethers_1.ethers.Interface.from([
64
+ 'function transfer(address to, uint256 amount)'
65
+ ]).encodeFunctionData('transfer', [
66
+ to,
67
+ ethers_1.ethers.parseUnits(amount, tokenDecimals)
68
+ ])
69
+ };
70
+ console.log(`Transferring ${amount} tokens to ${to}...`);
71
+ const result = await sdk.sendUserOperationAndWait(eoa, transferRequest, signFunction);
72
+ if (result.status.status === 'success') {
73
+ return {
74
+ success: true,
75
+ transactionHash: result.status.transactionHash,
76
+ message: 'Transfer successful'
77
+ };
78
+ }
79
+ else {
80
+ return {
81
+ success: false,
82
+ error: result.status.reason,
83
+ message: 'Transfer failed'
84
+ };
85
+ }
86
+ }
87
+ catch (error) {
88
+ const aaError = handleAAError(error);
89
+ return {
90
+ success: false,
91
+ error: aaError,
92
+ message: 'Transfer failed'
93
+ };
70
94
  }
71
- console.log(`✅ Using deployed proxy address: ${deployedProxyAddress}`);
72
- // 2. Configure Spending Rules
73
- console.log('\n--- Test 2: Configure Spending Rules ---');
74
- await ConfigureSpendingRules(sdk, eoa, deployedProxyAddress, signFunction);
75
- // 3. View Spending Rules
76
- console.log('\n--- Test 3: View Spending Rules ---');
77
- await ViewSpendingRules(sdk, deployedProxyAddress);
78
- // 4. Withdraw Funds
79
- console.log('\n--- Test 4: Withdraw Funds ---');
80
- await WithdrawFunds(sdk, eoa, deployedProxyAddress, signFunction);
81
- // 5. Check Token Balance
82
- console.log('\n--- Test 5: Check Token Balance ---');
83
- await CheckTokenBalance(sdk, deployedProxyAddress);
84
95
  }
85
- exports.clientAgentVaultIntegrationTests = clientAgentVaultIntegrationTests;
96
+ exports.transferERC20 = transferERC20;
97
+ // =============================================================================
98
+ // 2. KITEPASS RELATED - ClientAgentVault Operations
99
+ // KitePass相关 - 客户端代理金库操作
100
+ // =============================================================================
86
101
  /**
87
- * Test 1: Deploy ClientAgentVault Proxy via AA wallet's performCreate
102
+ * 部署KitePass合约
103
+ *
104
+ * @param eoa - User's EOA address
105
+ * @param signFunction - Signing function from Privy
106
+ * @returns Deployed KitePass address
88
107
  */
89
- async function DeployClientAgentVaultProxy(sdk, eoa, aa, signFunction) {
108
+ async function deployKitePass(eoa, signFunction) {
109
+ const sdk = initializeSDK();
110
+ const aa = sdk.getAccountAddress(eoa);
90
111
  try {
91
- // Prepare initialization data for ClientAgentVault
112
+ // Prepare initialization data
92
113
  const initializeCallData = ethers_1.ethers.Interface.from([
93
114
  'function initialize(address allowedToken, address owner)'
94
115
  ]).encodeFunctionData('initialize', [
95
116
  ADDRESSES.SETTLEMENT_TOKEN,
96
- aa // owner (AA wallet address)
117
+ aa
97
118
  ]);
98
- // Create TransparentUpgradeableProxy deployment bytecode
99
- // constructor(address _logic, address admin_, bytes memory _data)
100
- const proxyConstructorData = ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(['address', 'address', 'bytes'], [
101
- ADDRESSES.CLIENT_AGENT_VAULT_IMPL,
102
- aa,
103
- initializeCallData // initialization data
104
- ]);
105
- // Full deployment bytecode = creation code + constructor params
119
+ // Create KitePass deployment bytecode
120
+ const proxyConstructorData = ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(['address', 'address', 'bytes'], [ADDRESSES.CLIENT_AGENT_VAULT_IMPL, aa, initializeCallData]);
106
121
  const transparentProxyBytecode = getTransparentProxyBytecode();
107
122
  const fullInitCode = transparentProxyBytecode + proxyConstructorData.slice(2);
108
- // Create UserOperation to call performCreate
109
123
  const deployRequest = {
110
124
  target: aa,
111
125
  value: 0n,
112
126
  callData: ethers_1.ethers.Interface.from([
113
127
  'function performCreate(uint256 value, bytes calldata initCode) returns (address)'
114
- ]).encodeFunctionData('performCreate', [
115
- 0n,
116
- fullInitCode // proxy deployment bytecode + constructor params
117
- ])
128
+ ]).encodeFunctionData('performCreate', [0n, fullInitCode])
118
129
  };
119
- console.log('Deploying ClientAgentVault proxy...');
120
- console.log('- Implementation:', ADDRESSES.CLIENT_AGENT_VAULT_IMPL);
121
- console.log('- AllowedToken:', ADDRESSES.SETTLEMENT_TOKEN);
130
+ console.log('Deploying KitePass proxy...');
122
131
  const result = await sdk.sendUserOperationAndWait(eoa, deployRequest, signFunction);
123
132
  if (result.status.status === 'success') {
124
- console.log('✅ Proxy deployed successfully!');
125
- console.log('Transaction hash:', result.status.transactionHash);
126
- // Parse the deployed proxy address from transaction logs
127
133
  const proxyAddress = await parseContractCreatedEvent(result.status.transactionHash);
128
- if (proxyAddress) {
129
- console.log('🎯 Deployed proxy address:', proxyAddress);
130
- return proxyAddress; // Return the actual proxy address
131
- }
132
- else {
133
- console.log('⚠️ Could not parse proxy address from logs');
134
- }
134
+ return {
135
+ success: true,
136
+ proxyAddress: proxyAddress || undefined
137
+ };
135
138
  }
136
139
  else {
137
- console.log('❌ Deployment failed:', result.status.reason);
140
+ return {
141
+ success: false,
142
+ error: result.status.reason
143
+ };
138
144
  }
139
145
  }
140
146
  catch (error) {
141
- console.error('❌ Test 1 failed:', error);
147
+ return {
148
+ success: false,
149
+ error: handleAAError(error)
150
+ };
142
151
  }
143
- return null;
144
152
  }
145
- exports.DeployClientAgentVaultProxy = DeployClientAgentVaultProxy;
153
+ exports.deployKitePass = deployKitePass;
146
154
  /**
147
- * Test 2: Configure Spending Rules
155
+ * Configure spending rules for KitePass
156
+ * setSpendingRules方法会先清除现有的rules,然后设置新的rules
157
+ * 1. 新增/修改:需要先获取现有的rules,然后append新的rules,或者在现有rules的基础上修改
158
+ * 2. 删除:需要先获取现有的rules,然后删除对应的rules
159
+ *
160
+ * @param eoa - User's EOA address
161
+ * @param kitepassAddress - KitePass proxy address
162
+ * @param rules - Spending rules to configure
163
+ * @param signFunction - Signing function
148
164
  */
149
- async function ConfigureSpendingRules(sdk, owner, proxyAddress, signFunction) {
150
- // get today's 00:00:00 timestamp
151
- const today = new Date();
152
- const todayStart = new Date(today.getFullYear(), today.getMonth(), today.getDate());
153
- const todayStartTimestamp = Math.floor(todayStart.getTime() / 1000);
154
- // get current week's monday 00:00:00 timestamp
155
- const dayOfWeek = today.getDay(); // 0=Sunday, 1=Monday, ..., 6=Saturday
156
- const daysFromMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; // Convert Sunday=0 to Sunday=6
157
- const currentWeekStartTimestamp = todayStartTimestamp - (daysFromMonday * 86400); // 86400 = seconds in a day
158
- // rules fields:
159
- // - TimeWindow: time window in seconds, 0 means per transaction, >0 means per time window
160
- // - Budget: budget in wei, 18 decimals, like 1e18 means 1 token
161
- // - InitialWindowStartTime: start time of the time window in unix timestamp
162
- // should be set to the start time of the day/week/month in local time (or utc) 00:00:00
163
- // - TargetProviders: target service providers array, empty array means applies to all providers
165
+ async function configureSpendingRules(eoa, kitepassAddress, signFunction) {
166
+ const sdk = initializeSDK();
164
167
  try {
165
- // Define spending rules
168
+ // Convert rules to contract format
169
+ const today = new Date();
170
+ const todayStart = new Date(today.getFullYear(), today.getMonth(), today.getDate());
171
+ const todayStartTimestamp = Math.floor(todayStart.getTime() / 1000);
172
+ // get current week's monday 00:00:00 timestamp
173
+ const dayOfWeek = today.getDay(); // 0=Sunday, 1=Monday, ..., 6=Saturday
174
+ const daysFromMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; // Convert Sunday=0 to Sunday=6
175
+ const currentWeekStartTimestamp = todayStartTimestamp - (daysFromMonday * 86400); // 86400 = seconds in a day
176
+ // rules fields:
177
+ // - TimeWindow: time window in seconds, 0 means per transaction, >0 means per time window
178
+ // - Budget: budget in wei, 18 decimals, like 1e18 means 1 token
179
+ // - InitialWindowStartTime: start time of the time window in unix timestamp
180
+ // should be set to the start time of the day/week/month in local time (or utc) 00:00:00
181
+ // - TargetProviders: target service providers array, empty array means applies to all providers
166
182
  const rulesToAdd = [
167
183
  {
168
184
  timeWindow: 86400n,
@@ -183,201 +199,218 @@ async function ConfigureSpendingRules(sdk, owner, proxyAddress, signFunction) {
183
199
  targetProviders: [ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes('provider1'))]
184
200
  }
185
201
  ];
202
+ // 获取现有的rules
203
+ const existingRules = await viewSpendingRules(kitepassAddress);
204
+ const existingRulesArray = existingRules.rules;
205
+ // append new rules
206
+ const newRules = [...existingRulesArray, ...rulesToAdd];
186
207
  const configureRequest = {
187
- target: proxyAddress,
208
+ target: kitepassAddress,
188
209
  value: 0n,
189
210
  callData: ethers_1.ethers.Interface.from([
190
- 'function configureSpendingRule(uint256[] calldata indicesToRemove, tuple(uint256 timeWindow, uint160 budget, uint96 initialWindowStartTime, bytes32[] targetProviders)[] calldata rulesToAdd)'
191
- ]).encodeFunctionData('configureSpendingRule', [
192
- [],
193
- rulesToAdd // rules to add
194
- ])
211
+ 'function setSpendingRules(tuple(uint256 timeWindow, uint160 budget, uint96 initialWindowStartTime, bytes32[] targetProviders)[] calldata rules)'
212
+ ]).encodeFunctionData('setSpendingRules', [newRules])
195
213
  };
196
214
  console.log('Configuring spending rules...');
197
- console.log('- Rule 1: 100 tokens per 24 hours (all providers)');
198
- console.log('- Rule 2: 10 tokens per hour (specific provider)');
199
- const result = await sdk.sendUserOperationAndWait(owner, configureRequest, signFunction);
215
+ const result = await sdk.sendUserOperationAndWait(eoa, configureRequest, signFunction);
200
216
  if (result.status.status === 'success') {
201
- console.log('✅ Spending rules configured successfully!');
202
- console.log('Transaction hash:', result.status.transactionHash);
217
+ return {
218
+ success: true,
219
+ transactionHash: result.status.transactionHash
220
+ };
203
221
  }
204
222
  else {
205
- console.log('❌ Configuration failed:', result.status.reason);
223
+ return {
224
+ success: false,
225
+ error: result.status.reason
226
+ };
206
227
  }
207
228
  }
208
229
  catch (error) {
209
- const aaError = handleAAError(error);
210
- console.error('❌ Test 2 failed:', {
211
- type: aaError.type,
212
- message: aaError.message
213
- });
214
- // Frontend can handle different error types
215
- switch (aaError.type) {
216
- case 'ESTIMATE_GAS_FAILED':
217
- console.log('Suggestion: Check if the contract call is valid');
218
- break;
219
- case 'SEND_USEROP_FAILED':
220
- console.log('Suggestion: Try again or check bundler status');
221
- break;
222
- case 'NETWORK_ERROR':
223
- console.log('Suggestion: Check your internet connection');
224
- break;
225
- default:
226
- console.log('Suggestion: Check console for more details');
227
- }
230
+ return {
231
+ success: false,
232
+ error: handleAAError(error)
233
+ };
228
234
  }
229
235
  }
230
- exports.ConfigureSpendingRules = ConfigureSpendingRules;
236
+ exports.configureSpendingRules = configureSpendingRules;
231
237
  /**
232
- * Test 3: View Spending Rules (Read-only, no transaction sent)
238
+ * View current spending rules (read-only)
239
+ * 查看当前消费规则(只读)
233
240
  */
234
- async function ViewSpendingRules(sdk, proxyAddress) {
241
+ async function viewSpendingRules(kitepassAddress) {
235
242
  try {
236
243
  const provider = new ethers_1.ethers.JsonRpcProvider('https://rpc-testnet.gokite.ai');
237
- const contract = new ethers_1.ethers.Contract(proxyAddress, [
244
+ const contract = new ethers_1.ethers.Contract(kitepassAddress, [
238
245
  'function getSpendingRules() view returns (tuple(tuple(uint256 timeWindow, uint160 budget, uint96 initialWindowStartTime, bytes32[] targetProviders) rule, tuple(uint128 amountUsed, uint128 currentTimeWindowStartTime) usage)[])'
239
246
  ], provider);
240
- console.log('Fetching spending rules...');
241
247
  const spendingRules = await contract.getSpendingRules();
242
- console.log('✅ Spending Rules:');
243
- spendingRules.forEach((rule, index) => {
244
- console.log(` Rule ${index + 1}:`);
245
- console.log(` - Time Window: ${rule.rule.timeWindow} seconds`);
246
- console.log(` - Budget: ${ethers_1.ethers.formatUnits(rule.rule.budget, 18)} tokens`);
247
- console.log(` - Used: ${ethers_1.ethers.formatUnits(rule.usage.amountUsed, 18)} tokens`);
248
- console.log(` - Providers: ${rule.rule.targetProviders.length === 0 ? 'All' : rule.rule.targetProviders.length}`);
249
- });
248
+ return {
249
+ success: true,
250
+ rules: spendingRules.map((rule, index) => ({
251
+ index,
252
+ timeWindow: Number(rule.rule.timeWindow),
253
+ budget: ethers_1.ethers.formatUnits(rule.rule.budget, 18),
254
+ used: ethers_1.ethers.formatUnits(rule.usage.amountUsed, 18),
255
+ providersCount: rule.rule.targetProviders.length
256
+ }))
257
+ };
250
258
  }
251
259
  catch (error) {
252
- console.error('❌ Test 3 failed:', error);
260
+ return {
261
+ success: false,
262
+ error: error.message
263
+ };
253
264
  }
254
265
  }
255
- exports.ViewSpendingRules = ViewSpendingRules;
266
+ exports.viewSpendingRules = viewSpendingRules;
256
267
  /**
257
- * Test 4: Withdraw Funds
268
+ * Withdraw funds from KitePass
269
+ * 从KitePass提取资金
258
270
  */
259
- async function WithdrawFunds(sdk, owner, proxyAddress, signFunction) {
271
+ async function withdrawFunds(eoa, kitepassAddress, amount, tokenAddress = ADDRESSES.SETTLEMENT_TOKEN, signFunction) {
272
+ const sdk = initializeSDK();
260
273
  try {
261
- const withdrawAmount = ethers_1.ethers.parseUnits('50', 18); // Withdraw 50 tokens
262
274
  const withdrawRequest = {
263
- target: proxyAddress,
275
+ target: kitepassAddress,
264
276
  value: 0n,
265
277
  callData: ethers_1.ethers.Interface.from([
266
278
  'function withdrawFunds(address token, uint256 amount)'
267
279
  ]).encodeFunctionData('withdrawFunds', [
268
- ADDRESSES.SETTLEMENT_TOKEN,
269
- withdrawAmount // amount to withdraw
280
+ tokenAddress,
281
+ ethers_1.ethers.parseUnits(amount, 18)
270
282
  ])
271
283
  };
272
- console.log('Withdrawing funds...');
273
- console.log(`- Token: ${ADDRESSES.SETTLEMENT_TOKEN}`);
274
- console.log(`- Amount: ${ethers_1.ethers.formatUnits(withdrawAmount, 18)} tokens`);
275
- const result = await sdk.sendUserOperationAndWait(owner, withdrawRequest, signFunction);
284
+ console.log(`Withdrawing ${amount} tokens...`);
285
+ const result = await sdk.sendUserOperationAndWait(eoa, withdrawRequest, signFunction);
276
286
  if (result.status.status === 'success') {
277
- console.log('✅ Funds withdrawn successfully!');
278
- console.log('Transaction hash:', result.status.transactionHash);
287
+ return {
288
+ success: true,
289
+ transactionHash: result.status.transactionHash
290
+ };
279
291
  }
280
292
  else {
281
- console.log('❌ Withdrawal failed:', result.status.reason);
293
+ return {
294
+ success: false,
295
+ error: result.status.reason
296
+ };
282
297
  }
283
298
  }
284
299
  catch (error) {
285
- console.error('❌ Test 4 failed:', error);
300
+ return {
301
+ success: false,
302
+ error: handleAAError(error)
303
+ };
286
304
  }
287
305
  }
288
- exports.WithdrawFunds = WithdrawFunds;
306
+ exports.withdrawFunds = withdrawFunds;
289
307
  /**
290
- * Test 5: Check Token Balance (Read-only)
308
+ * Check token balance (read-only)
309
+ * 查看代币余额(只读)
291
310
  */
292
- async function CheckTokenBalance(sdk, proxyAddress) {
311
+ async function checkTokenBalance(address, tokenAddress = ADDRESSES.SETTLEMENT_TOKEN) {
293
312
  try {
294
313
  const provider = new ethers_1.ethers.JsonRpcProvider('https://rpc-testnet.gokite.ai');
295
- const tokenContract = new ethers_1.ethers.Contract(ADDRESSES.SETTLEMENT_TOKEN, [
314
+ const tokenContract = new ethers_1.ethers.Contract(tokenAddress, [
296
315
  'function balanceOf(address account) view returns (uint256)',
297
316
  'function symbol() view returns (string)',
298
317
  'function decimals() view returns (uint8)'
299
318
  ], provider);
300
- console.log('Checking token balance...');
301
319
  const [balance, symbol, decimals] = await Promise.all([
302
- tokenContract.balanceOf(proxyAddress),
320
+ tokenContract.balanceOf(address),
303
321
  tokenContract.symbol(),
304
322
  tokenContract.decimals()
305
323
  ]);
306
- console.log('✅ Token Balance:');
307
- console.log(` - Address: ${proxyAddress}`);
308
- console.log(` - Token: ${symbol} (${ADDRESSES.SETTLEMENT_TOKEN})`);
309
- console.log(` - Balance: ${ethers_1.ethers.formatUnits(balance, decimals)} ${symbol}`);
324
+ return {
325
+ success: true,
326
+ balance: ethers_1.ethers.formatUnits(balance, decimals),
327
+ symbol,
328
+ decimals,
329
+ address
330
+ };
310
331
  }
311
332
  catch (error) {
312
- console.error('❌ Test 5 failed:', error);
333
+ return {
334
+ success: false,
335
+ error: error.message
336
+ };
313
337
  }
314
338
  }
315
- exports.CheckTokenBalance = CheckTokenBalance;
339
+ exports.checkTokenBalance = checkTokenBalance;
316
340
  /**
317
- * Legacy example for basic AA operations
341
+ * Register a service in the service registry
342
+ * 在服务注册表中注册服务
343
+ *
344
+ * @param eoa - Service owner's EOA address
345
+ * @param serviceId - Service ID (bytes32)
346
+ * @param serviceInfo - Service information
347
+ * @param signFunction - Signing function
318
348
  */
319
- async function basicExample() {
320
- console.log('\n=== Basic AA SDK Example ===');
321
- // Initialize SDK
322
- const sdk = new gokite_aa_sdk_1.GokiteAASDK('kite_testnet', 'https://rpc-testnet.gokite.ai', 'http://localhost:14337/rpc/');
323
- const owner = '0x4A50DCA63d541372ad36E5A36F1D542d51164F19';
324
- const accountAddress = sdk.getAccountAddress(owner);
325
- console.log('Account address:', accountAddress);
326
- // Simple ETH transfer example
327
- const sendEthRequest = {
328
- target: '0x4A50DCA63d541372ad36E5A36F1D542d51164F19',
329
- value: ethers_1.ethers.parseEther('0.001'),
330
- callData: '0x'
331
- };
332
- const signFunction = async (userOpHash) => {
333
- const signer_pk = process.env.PRIVATE_KEY;
334
- const signer = new ethers_1.ethers.Wallet(signer_pk);
335
- return signer.signMessage(ethers_1.ethers.getBytes(userOpHash));
336
- };
349
+ async function registerService(eoa, serviceId, serviceInfo, signFunction) {
350
+ const sdk = initializeSDK();
337
351
  try {
338
- const result = await sdk.sendUserOperationAndWait(owner, sendEthRequest, signFunction);
352
+ const registerRequest = {
353
+ target: ADDRESSES.SERVICE_REGISTRY,
354
+ value: 0n,
355
+ callData: ethers_1.ethers.Interface.from([
356
+ 'function registerService(bytes32 serviceId, tuple(address serviceOwner, uint8 priceModel, uint256 unitPrice, bytes32 provider, bytes metadata, string name, bool isPublic) service)'
357
+ ]).encodeFunctionData('registerService', [
358
+ serviceId,
359
+ serviceInfo
360
+ ])
361
+ };
362
+ console.log(`Registering service: ${serviceInfo.name}...`);
363
+ const result = await sdk.sendUserOperationAndWait(eoa, registerRequest, signFunction);
339
364
  if (result.status.status === 'success') {
340
- console.log('✅ ETH transfer successful!');
341
- console.log('Transaction hash:', result.status.transactionHash);
365
+ return {
366
+ success: true,
367
+ transactionHash: result.status.transactionHash,
368
+ serviceId
369
+ };
342
370
  }
343
371
  else {
344
- console.log('❌ ETH transfer failed:', result.status.reason);
372
+ return {
373
+ success: false,
374
+ error: result.status.reason
375
+ };
345
376
  }
346
377
  }
347
378
  catch (error) {
348
- console.error('❌ Basic example failed:', error);
379
+ return {
380
+ success: false,
381
+ error: handleAAError(error)
382
+ };
349
383
  }
350
384
  }
351
- exports.basicExample = basicExample;
385
+ exports.registerService = registerService;
386
+ // =============================================================================
387
+ // UTILITY FUNCTIONS - 工具函数
388
+ // =============================================================================
389
+ /**
390
+ * Get TransparentUpgradeableProxy bytecode
391
+ * 获取透明可升级代理字节码
392
+ */
393
+ function getTransparentProxyBytecode() {
394
+ return '0x60a0604052610b278038038061001481610293565b928339810160608282031261028e5761002c826102b8565b610038602084016102b8565b604084015190936001600160401b03821161028e570182601f8201121561028e5780519061006d610068836102cc565b610293565b938285526020838301011161028e5760005b828110610279575050602060009184010152803b15610258577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0383169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a281511561023f5760008083602061013595519101845af43d15610237573d91610125610068846102cc565b9283523d6000602085013e6102e7565b505b604051906104918083016001600160401b0381118482101761022157602092849261067684396001600160a01b031681520301906000f080156102155760018060a01b031680608052600080516020610b07833981519152547f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6040805160018060a01b0384168152846020820152a181156101ff576001600160a01b03191617600080516020610b078339815191525560405161032d908161034982396080518160070152f35b633173bdd160e11b600052600060045260246000fd5b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b6060916102e7565b505034156101375763b398979f60e01b60005260046000fd5b634c9c8ce360e01b60009081526001600160a01b0391909116600452602490fd5b8060208092840101518282880101520161007f565b600080fd5b6040519190601f01601f191682016001600160401b0381118382101761022157604052565b51906001600160a01b038216820361028e57565b6001600160401b03811161022157601f01601f191660200190565b9061030d57508051156102fc57805190602001fd5b630a12f52160e11b60005260046000fd5b8151158061033f575b61031e575090565b639996b31560e01b60009081526001600160a01b0391909116600452602490fd5b50803b1561031656fe6080604052337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610069576000356001600160e01b03191663278f794360e11b1461005f576334ad5dbb60e21b60005260046000fd5b610067610113565b005b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5460009081906001600160a01b0316368280378136915af43d6000803e156100b1573d6000f35b3d6000fd5b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f1916820167ffffffffffffffff8111838210176100f257604052565b6100b6565b67ffffffffffffffff81116100f257601f01601f191660200190565b3660041161019d57604036600319011261019d576004356001600160a01b0381169081900361019d576024359067ffffffffffffffff821161019d573660238301121561019d5781600401359061017161016c836100f7565b6100cc565b91808352366024828601011161019d57602081600092602461019b970183870137840101526101a2565b565b600080fd5b90813b15610239577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a280511561021f5761021c9161025b565b50565b50503461022857565b63b398979f60e01b60005260046000fd5b50634c9c8ce360e01b60009081526001600160a01b0391909116600452602490fd5b60008061028f93602081519101845af43d15610292573d9161027f61016c846100f7565b9283523d6000602085013e610296565b90565b6060915b906102bc57508051156102ab57805190602001fd5b630a12f52160e11b60005260046000fd5b815115806102ee575b6102cd575090565b639996b31560e01b60009081526001600160a01b0391909116600452602490fd5b50803b156102c556fea2646970667358221220597147005a6fe654561cbab25a93153cc233180473a65a90bd427f0c1f41018764736f6c634300081c003360803460bc57601f61049138819003918201601f19168301916001600160401b0383118484101760c15780849260209460405283398101031260bc57516001600160a01b0381169081900360bc57801560a657600080546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36103b990816100d88239f35b631e4fbdf760e01b600052600060045260246000fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe6080604052600436101561001257600080fd5b6000803560e01c8063715018a6146102875780638da5cb5b146102605780639623609d1461012f578063ad3cb1cc146100e25763f2fde38b1461005457600080fd5b346100df5760203660031901126100df576004356001600160a01b038116908190036100dd5761008261035a565b80156100c95781546001600160a01b03198116821783556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b631e4fbdf760e01b82526004829052602482fd5b505b80fd5b50346100df57806003193601126100df575061012b6040516101056040826102e1565b60058152640352e302e360dc1b6020820152604051918291602083526020830190610319565b0390f35b5060603660031901126100df576004356001600160a01b038116908190036100dd576024356001600160a01b038116908190036102405760443567ffffffffffffffff811161025c573660238201121561025c57806004013567ffffffffffffffff8111610248576040518593929091906101b4601f8301601f1916602001846102e1565b81835236602483830101116102445781859260246020930183860137830101526101dc61035a565b833b156102405761021293839260405180968194829363278f794360e11b84526004840152604060248401526044830190610319565b039134905af18015610233576102255780f35b61022e916102e1565b388180f35b50604051903d90823e3d90fd5b8280fd5b8480fd5b634e487b7160e01b85526041600452602485fd5b8380fd5b50346100df57806003193601126100df57546040516001600160a01b039091168152602090f35b50346100df57806003193601126100df576102a061035a565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b90601f8019910116810190811067ffffffffffffffff82111761030357604052565b634e487b7160e01b600052604160045260246000fd5b919082519283825260005b848110610345575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201610324565b6000546001600160a01b0316330361036e57565b63118cdaa760e01b6000523360045260246000fdfea26469706673582212207bc32ec723f6be34b228b59aef2ef61b4e6a8eb5bc67fcdd495248566e3b6e0c64736f6c634300081c0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103';
395
+ }
396
+ exports.getTransparentProxyBytecode = getTransparentProxyBytecode;
352
397
  /**
353
- * Parse ContractCreated event from transaction logs to get deployed proxy address
354
- * Event: ContractCreated(address indexed contractAddress)
398
+ * Parse ContractCreated event from transaction logs
399
+ * 从交易日志中解析合约创建事件
355
400
  */
356
401
  async function parseContractCreatedEvent(transactionHash) {
357
402
  try {
358
403
  const provider = new ethers_1.ethers.JsonRpcProvider('https://rpc-testnet.gokite.ai');
359
404
  const receipt = await provider.getTransactionReceipt(transactionHash);
360
- if (!receipt) {
361
- console.error('Transaction receipt not found');
405
+ if (!receipt)
362
406
  return null;
363
- }
364
- // ContractCreated event signature: ContractCreated(address indexed contractAddress)
365
407
  const contractCreatedEventSignature = ethers_1.ethers.id('ContractCreated(address)');
366
- console.log('Parsing transaction logs...');
367
- console.log(`Total logs: ${receipt.logs.length}`);
368
408
  for (const log of receipt.logs) {
369
- // Check if this log matches the ContractCreated event
370
409
  if (log.topics[0] === contractCreatedEventSignature) {
371
- // The first topic is the event signature
372
- // The second topic is the indexed contractAddress
373
410
  const contractAddress = ethers_1.ethers.AbiCoder.defaultAbiCoder().decode(['address'], log.topics[1])[0];
374
- console.log('Found ContractCreated event:');
375
- console.log('- Contract Address:', contractAddress);
376
- console.log('- From Address:', log.address);
377
411
  return contractAddress;
378
412
  }
379
413
  }
380
- console.log('No ContractCreated event found in transaction logs');
381
414
  return null;
382
415
  }
383
416
  catch (error) {
@@ -385,13 +418,63 @@ async function parseContractCreatedEvent(transactionHash) {
385
418
  return null;
386
419
  }
387
420
  }
388
- async function main() {
389
- // Run ClientAgentVault integration tests
390
- await clientAgentVaultIntegrationTests();
391
- // // Run basic AA example
392
- // await basicExample();
393
- console.log('\n✅ All examples completed!');
421
+ exports.parseContractCreatedEvent = parseContractCreatedEvent;
422
+ // =============================================================================
423
+ // EXAMPLE USAGE - 使用示例
424
+ // =============================================================================
425
+ /**
426
+ * Example usage for frontend integration
427
+ * 前端集成使用示例
428
+ */
429
+ async function exampleUsage() {
430
+ // Replace with actual signing function from Privy/Particle
431
+ // 替换为实际的Privy/Particle签名函数
432
+ const signFunction = async (userOpHash) => {
433
+ const signer_pk = process.env.PRIVATE_KEY;
434
+ const signer = new ethers_1.ethers.Wallet(signer_pk);
435
+ return signer.signMessage(ethers_1.ethers.getBytes(userOpHash));
436
+ };
437
+ const userEoa = '0x4A50DCA63d541372ad36E5A36F1D542d51164F19';
438
+ // actual token recipient address
439
+ const toAddress = '0x4A50DCA63d541372ad36E5A36F1D542d51164F19';
440
+ // 1. Transfer ERC20 tokens
441
+ console.log('\n=== 1. ERC20 Transfer ===');
442
+ const transferResult = await transferERC20(userEoa, toAddress, '10', ADDRESSES.SETTLEMENT_TOKEN, 18, signFunction);
443
+ console.log('Transfer result:', transferResult);
444
+ // 2. Deploy KitePass
445
+ console.log('\n=== 2. Deploy KitePass ===');
446
+ const deployResult = await deployKitePass(userEoa, signFunction);
447
+ console.log('Deploy result:', deployResult);
448
+ if (deployResult.success && deployResult.proxyAddress) {
449
+ // 3. Configure spending rules
450
+ console.log('\n=== 3. Configure Spending Rules ===');
451
+ const configResult = await configureSpendingRules(userEoa, deployResult.proxyAddress, signFunction);
452
+ console.log('Config result:', configResult);
453
+ // 4. View spending rules
454
+ console.log('\n=== 4. View Spending Rules ===');
455
+ const rulesResult = await viewSpendingRules(deployResult.proxyAddress);
456
+ console.log('Rules result:', rulesResult);
457
+ }
458
+ // 5. Register service
459
+ console.log('\n=== 5. Register Service ===');
460
+ // serviceId, get from backend
461
+ const serviceId = ethers_1.ethers.hexlify((0, ethers_1.randomBytes)(32));
462
+ const sdk = initializeSDK();
463
+ const serviceOwner = sdk.getAccountAddress(userEoa);
464
+ const serviceResult = await registerService(userEoa, serviceId, {
465
+ serviceOwner: serviceOwner,
466
+ priceModel: 0,
467
+ unitPrice: 100,
468
+ // provider Id, bytes32
469
+ provider: ethers_1.ethers.hexlify((0, ethers_1.randomBytes)(32)),
470
+ // service metadata, currently not used
471
+ metadata: '0x',
472
+ name: 'Test Service',
473
+ isPublic: true
474
+ }, signFunction);
475
+ console.log('Service result:', serviceResult);
476
+ }
477
+ // Run example if executed directly
478
+ if (require.main === module) {
479
+ exampleUsage().catch(console.error);
394
480
  }
395
- // Legacy export for backwards compatibility
396
- exports.example = basicExample;
397
- main().catch(console.error);