gokite-aa-sdk 1.0.0
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/README.md +141 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.js +12 -0
- package/dist/example.d.ts +47 -0
- package/dist/example.js +397 -0
- package/dist/gokite-aa-sdk.d.ts +70 -0
- package/dist/gokite-aa-sdk.js +428 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +23 -0
- package/dist/types.d.ts +95 -0
- package/dist/types.js +13 -0
- package/dist/utils.d.ts +49 -0
- package/dist/utils.js +156 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Gokite AA SDK
|
|
2
|
+
|
|
3
|
+
Account Abstraction (EIP-4337) SDK for Gokite.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install gokite-aa-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { GokiteAASDK } from 'gokite-aa-sdk';
|
|
15
|
+
import { ethers } from 'ethers';
|
|
16
|
+
|
|
17
|
+
// Initialize SDK
|
|
18
|
+
const sdk = new GokiteAASDK(
|
|
19
|
+
'kite_testnet',
|
|
20
|
+
'https://rpc-testnet.gokite.ai',
|
|
21
|
+
'http://localhost:14337/rpc/' // bundler URL
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
// Owner address (from your social login SDK)
|
|
25
|
+
const owner = '0x...';
|
|
26
|
+
|
|
27
|
+
// Get account address (can get aa wallet address even if the wallet is not deployed)
|
|
28
|
+
const accountAddress = sdk.getAccountAddress(owner);
|
|
29
|
+
|
|
30
|
+
// Sign function - integrate with your social login SDK
|
|
31
|
+
const signFunction = async (userOpHash: string): Promise<string> => {
|
|
32
|
+
// Use your preferred signing method (Particle, Privy, etc.)
|
|
33
|
+
return await signer.sign(ethers.getBytes(userOpHash));
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Send transaction
|
|
37
|
+
const userOpHash = await sdk.sendUserOperation(
|
|
38
|
+
owner,
|
|
39
|
+
{
|
|
40
|
+
target: '0x...',
|
|
41
|
+
value: ethers.parseEther('0.1'),
|
|
42
|
+
callData: '0x'
|
|
43
|
+
},
|
|
44
|
+
signFunction
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// Wait for confirmation
|
|
48
|
+
const status = await sdk.pollUserOperationStatus(userOpHash);
|
|
49
|
+
console.log('Transaction status:', status);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## API Reference
|
|
53
|
+
|
|
54
|
+
### GokiteAASDK
|
|
55
|
+
|
|
56
|
+
#### Constructor
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
new GokiteAASDK(network: string, rpcUrl: string, bundlerUrl?: string)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Methods
|
|
63
|
+
|
|
64
|
+
- `getAccountAddress(owner: string, salt?: bigint): string` - Calculate account address
|
|
65
|
+
- `sendUserOperation(owner: string, request: UserOperationRequest | BatchUserOperationRequest, signFn: SignFunction, salt?: bigint, paymasterAddress?: string): Promise<string>` - Send transaction
|
|
66
|
+
- `pollUserOperationStatus(userOpHash: string, options: PollingOptions = {}): Promise<UserOperationStatus>` - Wait for confirmation
|
|
67
|
+
- `isAccountDeloyed(accountAddress: string): Promise<boolean>` - Check if account is deployed
|
|
68
|
+
|
|
69
|
+
### Types
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
interface UserOperationRequest {
|
|
73
|
+
target: string;
|
|
74
|
+
value?: bigint;
|
|
75
|
+
callData: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface BatchUserOperationRequest {
|
|
79
|
+
targets: string[];
|
|
80
|
+
values?: bigint[];
|
|
81
|
+
callDatas: string[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface SignFunction {
|
|
85
|
+
(userOpHash: string): Promise<string>;
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Examples
|
|
90
|
+
|
|
91
|
+
### Single Transaction
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
const request = {
|
|
95
|
+
target: '0x...',
|
|
96
|
+
value: ethers.parseEther('0.1'),
|
|
97
|
+
callData: '0x'
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const userOpHash = await sdk.sendUserOperation(owner, request, signFunction);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Batch Transactions
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
const batchRequest = {
|
|
107
|
+
targets: ['0x...', '0x...'],
|
|
108
|
+
values: [ethers.parseEther('0.1'), 0n],
|
|
109
|
+
callDatas: ['0x', '0x...']
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const userOpHash = await sdk.sendUserOperation(owner, batchRequest, signFunction);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Integration with Particle
|
|
116
|
+
|
|
117
|
+
#### docs:
|
|
118
|
+
|
|
119
|
+
https://developers.particle.network/api-reference/auth/desktop-sdks/web#personal-signatures
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// After configuring AuthCoreContextProvider and logging in
|
|
123
|
+
const { signMessage } = useEthereum();
|
|
124
|
+
|
|
125
|
+
const signFunction = async (userOpHash: string): Promise<string> => {
|
|
126
|
+
return await signMessage(userOpHash)
|
|
127
|
+
};
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Supported Networks
|
|
131
|
+
|
|
132
|
+
- **kite_testnet**: Kite Testnet (Chain ID: 2368)
|
|
133
|
+
|
|
134
|
+
## Requirements
|
|
135
|
+
|
|
136
|
+
- Node.js >= 16
|
|
137
|
+
- ethers >= 6.0.0
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NETWORKS = void 0;
|
|
4
|
+
exports.NETWORKS = {
|
|
5
|
+
kite_testnet: {
|
|
6
|
+
chainId: 2368,
|
|
7
|
+
entryPoint: '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108',
|
|
8
|
+
accountFactory: '0xF0Fc19F0dc393867F19351d25EDfc5E099561cb7',
|
|
9
|
+
accountImplementation: '0x93F5310eFd0f09db0666CA5146E63CA6Cdc6FC21',
|
|
10
|
+
paymaster: '0x122E0e1F7fFc0f5d64F5470CF42c6bA0abdF7158',
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { GokiteAASDK } from './gokite-aa-sdk';
|
|
2
|
+
import "dotenv/config";
|
|
3
|
+
declare function handleAAError(error: any): {
|
|
4
|
+
type: string;
|
|
5
|
+
message: string;
|
|
6
|
+
details?: any;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* ClientAgentVault Integration Tests
|
|
10
|
+
*
|
|
11
|
+
* these tests show how to use the AA wallet to:
|
|
12
|
+
* 1. deploy the ClientAgentVault proxy contract (via performCreate)
|
|
13
|
+
* 2. configure spending rules (Spending Rules)
|
|
14
|
+
* 3. view spending rules (read-only)
|
|
15
|
+
* 4. withdraw funds (withdrawFunds)
|
|
16
|
+
* 5. check token balance (read-only)
|
|
17
|
+
*
|
|
18
|
+
* how to use:
|
|
19
|
+
* - modify the contract addresses and parameters as needed
|
|
20
|
+
*/
|
|
21
|
+
declare function clientAgentVaultIntegrationTests(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Test 1: Deploy ClientAgentVault Proxy via AA wallet's performCreate
|
|
24
|
+
*/
|
|
25
|
+
declare function DeployClientAgentVaultProxy(sdk: GokiteAASDK, eoa: string, aa: string, signFunction: any): Promise<string | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Test 2: Configure Spending Rules
|
|
28
|
+
*/
|
|
29
|
+
declare function ConfigureSpendingRules(sdk: GokiteAASDK, owner: string, proxyAddress: string, signFunction: any): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Test 3: View Spending Rules (Read-only, no transaction sent)
|
|
32
|
+
*/
|
|
33
|
+
declare function ViewSpendingRules(sdk: GokiteAASDK, proxyAddress: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Test 4: Withdraw Funds
|
|
36
|
+
*/
|
|
37
|
+
declare function WithdrawFunds(sdk: GokiteAASDK, owner: string, proxyAddress: string, signFunction: any): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Test 5: Check Token Balance (Read-only)
|
|
40
|
+
*/
|
|
41
|
+
declare function CheckTokenBalance(sdk: GokiteAASDK, proxyAddress: string): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Legacy example for basic AA operations
|
|
44
|
+
*/
|
|
45
|
+
declare function basicExample(): Promise<void>;
|
|
46
|
+
export { clientAgentVaultIntegrationTests, basicExample, DeployClientAgentVaultProxy, ConfigureSpendingRules, ViewSpendingRules, WithdrawFunds, CheckTokenBalance, handleAAError, };
|
|
47
|
+
export declare const example: typeof basicExample;
|
package/dist/example.js
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
"use strict";
|
|
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;
|
|
4
|
+
const gokite_aa_sdk_1 = require("./gokite-aa-sdk");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
const ethers_1 = require("ethers");
|
|
7
|
+
require("dotenv/config");
|
|
8
|
+
// Contract addresses on kite_testnet
|
|
9
|
+
const ADDRESSES = {
|
|
10
|
+
SETTLEMENT_TOKEN: '0x0fF5393387ad2f9f691FD6Fd28e07E3969e27e63',
|
|
11
|
+
SETTLEMENT_CONTRACT: '0x8d9FaD78d5Ce247aA01C140798B9558fd64a63E3',
|
|
12
|
+
CLIENT_AGENT_VAULT_IMPL: '0xB5AAFCC6DD4DFc2B80fb8BCcf406E1a2Fd559e23'
|
|
13
|
+
};
|
|
14
|
+
function handleAAError(error) {
|
|
15
|
+
if (error instanceof types_1.AASDKError) {
|
|
16
|
+
return {
|
|
17
|
+
type: error.type,
|
|
18
|
+
message: error.message,
|
|
19
|
+
details: error.details
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// Fallback for other errors
|
|
23
|
+
return {
|
|
24
|
+
type: 'UNKNOWN_ERROR',
|
|
25
|
+
message: error.message || 'An unknown error occurred',
|
|
26
|
+
details: error
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
exports.handleAAError = handleAAError;
|
|
30
|
+
/**
|
|
31
|
+
* Get TransparentUpgradeableProxy bytecode
|
|
32
|
+
*/
|
|
33
|
+
function getTransparentProxyBytecode() {
|
|
34
|
+
// This is the bytecode for TransparentUpgradeableProxy
|
|
35
|
+
return '0x60a0604052610b278038038061001481610293565b928339810160608282031261028e5761002c826102b8565b610038602084016102b8565b604084015190936001600160401b03821161028e570182601f8201121561028e5780519061006d610068836102cc565b610293565b938285526020838301011161028e5760005b828110610279575050602060009184010152803b15610258577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0383169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a281511561023f5760008083602061013595519101845af43d15610237573d91610125610068846102cc565b9283523d6000602085013e6102e7565b505b604051906104918083016001600160401b0381118482101761022157602092849261067684396001600160a01b031681520301906000f080156102155760018060a01b031680608052600080516020610b07833981519152547f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6040805160018060a01b0384168152846020820152a181156101ff576001600160a01b03191617600080516020610b078339815191525560405161032d908161034982396080518160070152f35b633173bdd160e11b600052600060045260246000fd5b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b6060916102e7565b505034156101375763b398979f60e01b60005260046000fd5b634c9c8ce360e01b60009081526001600160a01b0391909116600452602490fd5b8060208092840101518282880101520161007f565b600080fd5b6040519190601f01601f191682016001600160401b0381118382101761022157604052565b51906001600160a01b038216820361028e57565b6001600160401b03811161022157601f01601f191660200190565b9061030d57508051156102fc57805190602001fd5b630a12f52160e11b60005260046000fd5b8151158061033f575b61031e575090565b639996b31560e01b60009081526001600160a01b0391909116600452602490fd5b50803b1561031656fe6080604052337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603610069576000356001600160e01b03191663278f794360e11b1461005f576334ad5dbb60e21b60005260046000fd5b610067610113565b005b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5460009081906001600160a01b0316368280378136915af43d6000803e156100b1573d6000f35b3d6000fd5b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f1916820167ffffffffffffffff8111838210176100f257604052565b6100b6565b67ffffffffffffffff81116100f257601f01601f191660200190565b3660041161019d57604036600319011261019d576004356001600160a01b0381169081900361019d576024359067ffffffffffffffff821161019d573660238301121561019d5781600401359061017161016c836100f7565b6100cc565b91808352366024828601011161019d57602081600092602461019b970183870137840101526101a2565b565b600080fd5b90813b15610239577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a280511561021f5761021c9161025b565b50565b50503461022857565b63b398979f60e01b60005260046000fd5b50634c9c8ce360e01b60009081526001600160a01b0391909116600452602490fd5b60008061028f93602081519101845af43d15610292573d9161027f61016c846100f7565b9283523d6000602085013e610296565b90565b6060915b906102bc57508051156102ab57805190602001fd5b630a12f52160e11b60005260046000fd5b815115806102ee575b6102cd575090565b639996b31560e01b60009081526001600160a01b0391909116600452602490fd5b50803b156102c556fea2646970667358221220597147005a6fe654561cbab25a93153cc233180473a65a90bd427f0c1f41018764736f6c634300081c003360803460bc57601f61049138819003918201601f19168301916001600160401b0383118484101760c15780849260209460405283398101031260bc57516001600160a01b0381169081900360bc57801560a657600080546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36103b990816100d88239f35b631e4fbdf760e01b600052600060045260246000fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe6080604052600436101561001257600080fd5b6000803560e01c8063715018a6146102875780638da5cb5b146102605780639623609d1461012f578063ad3cb1cc146100e25763f2fde38b1461005457600080fd5b346100df5760203660031901126100df576004356001600160a01b038116908190036100dd5761008261035a565b80156100c95781546001600160a01b03198116821783556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b631e4fbdf760e01b82526004829052602482fd5b505b80fd5b50346100df57806003193601126100df575061012b6040516101056040826102e1565b60058152640352e302e360dc1b6020820152604051918291602083526020830190610319565b0390f35b5060603660031901126100df576004356001600160a01b038116908190036100dd576024356001600160a01b038116908190036102405760443567ffffffffffffffff811161025c573660238201121561025c57806004013567ffffffffffffffff8111610248576040518593929091906101b4601f8301601f1916602001846102e1565b81835236602483830101116102445781859260246020930183860137830101526101dc61035a565b833b156102405761021293839260405180968194829363278f794360e11b84526004840152604060248401526044830190610319565b039134905af18015610233576102255780f35b61022e916102e1565b388180f35b50604051903d90823e3d90fd5b8280fd5b8480fd5b634e487b7160e01b85526041600452602485fd5b8380fd5b50346100df57806003193601126100df57546040516001600160a01b039091168152602090f35b50346100df57806003193601126100df576102a061035a565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b90601f8019910116810190811067ffffffffffffffff82111761030357604052565b634e487b7160e01b600052604160045260246000fd5b919082519283825260005b848110610345575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201610324565b6000546001600160a01b0316330361036e57565b63118cdaa760e01b6000523360045260246000fdfea26469706673582212207bc32ec723f6be34b228b59aef2ef61b4e6a8eb5bc67fcdd495248566e3b6e0c64736f6c634300081c0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103';
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* ClientAgentVault Integration Tests
|
|
39
|
+
*
|
|
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
|
|
49
|
+
*/
|
|
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', 'http://localhost:14337/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;
|
|
70
|
+
}
|
|
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
|
+
}
|
|
85
|
+
exports.clientAgentVaultIntegrationTests = clientAgentVaultIntegrationTests;
|
|
86
|
+
/**
|
|
87
|
+
* Test 1: Deploy ClientAgentVault Proxy via AA wallet's performCreate
|
|
88
|
+
*/
|
|
89
|
+
async function DeployClientAgentVaultProxy(sdk, eoa, aa, signFunction) {
|
|
90
|
+
try {
|
|
91
|
+
// Prepare initialization data for ClientAgentVault
|
|
92
|
+
const initializeCallData = ethers_1.ethers.Interface.from([
|
|
93
|
+
'function initialize(address allowedToken, address owner)'
|
|
94
|
+
]).encodeFunctionData('initialize', [
|
|
95
|
+
ADDRESSES.SETTLEMENT_TOKEN,
|
|
96
|
+
aa // owner (AA wallet address)
|
|
97
|
+
]);
|
|
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
|
|
106
|
+
const transparentProxyBytecode = getTransparentProxyBytecode();
|
|
107
|
+
const fullInitCode = transparentProxyBytecode + proxyConstructorData.slice(2);
|
|
108
|
+
// Create UserOperation to call performCreate
|
|
109
|
+
const deployRequest = {
|
|
110
|
+
target: aa,
|
|
111
|
+
value: 0n,
|
|
112
|
+
callData: ethers_1.ethers.Interface.from([
|
|
113
|
+
'function performCreate(uint256 value, bytes calldata initCode) returns (address)'
|
|
114
|
+
]).encodeFunctionData('performCreate', [
|
|
115
|
+
0n,
|
|
116
|
+
fullInitCode // proxy deployment bytecode + constructor params
|
|
117
|
+
])
|
|
118
|
+
};
|
|
119
|
+
console.log('Deploying ClientAgentVault proxy...');
|
|
120
|
+
console.log('- Implementation:', ADDRESSES.CLIENT_AGENT_VAULT_IMPL);
|
|
121
|
+
console.log('- AllowedToken:', ADDRESSES.SETTLEMENT_TOKEN);
|
|
122
|
+
const result = await sdk.sendUserOperationAndWait(eoa, deployRequest, signFunction);
|
|
123
|
+
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
|
+
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
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
console.log('❌ Deployment failed:', result.status.reason);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
console.error('❌ Test 1 failed:', error);
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
exports.DeployClientAgentVaultProxy = DeployClientAgentVaultProxy;
|
|
146
|
+
/**
|
|
147
|
+
* Test 2: Configure Spending Rules
|
|
148
|
+
*/
|
|
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
|
|
164
|
+
try {
|
|
165
|
+
// Define spending rules
|
|
166
|
+
const rulesToAdd = [
|
|
167
|
+
{
|
|
168
|
+
timeWindow: 86400n,
|
|
169
|
+
budget: ethers_1.ethers.parseUnits('100', 18),
|
|
170
|
+
initialWindowStartTime: todayStartTimestamp,
|
|
171
|
+
targetProviders: [] // Empty means applies to all providers
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
timeWindow: 604800n,
|
|
175
|
+
budget: ethers_1.ethers.parseUnits('1000', 18),
|
|
176
|
+
initialWindowStartTime: currentWeekStartTimestamp,
|
|
177
|
+
targetProviders: []
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
timeWindow: 0,
|
|
181
|
+
budget: ethers_1.ethers.parseUnits('10', 18),
|
|
182
|
+
initialWindowStartTime: 0n,
|
|
183
|
+
targetProviders: [ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes('provider1'))]
|
|
184
|
+
}
|
|
185
|
+
];
|
|
186
|
+
const configureRequest = {
|
|
187
|
+
target: proxyAddress,
|
|
188
|
+
value: 0n,
|
|
189
|
+
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
|
+
])
|
|
195
|
+
};
|
|
196
|
+
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);
|
|
200
|
+
if (result.status.status === 'success') {
|
|
201
|
+
console.log('✅ Spending rules configured successfully!');
|
|
202
|
+
console.log('Transaction hash:', result.status.transactionHash);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
console.log('❌ Configuration failed:', result.status.reason);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
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
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
exports.ConfigureSpendingRules = ConfigureSpendingRules;
|
|
231
|
+
/**
|
|
232
|
+
* Test 3: View Spending Rules (Read-only, no transaction sent)
|
|
233
|
+
*/
|
|
234
|
+
async function ViewSpendingRules(sdk, proxyAddress) {
|
|
235
|
+
try {
|
|
236
|
+
const provider = new ethers_1.ethers.JsonRpcProvider('https://rpc-testnet.gokite.ai');
|
|
237
|
+
const contract = new ethers_1.ethers.Contract(proxyAddress, [
|
|
238
|
+
'function getSpendingRules() view returns (tuple(tuple(uint256 timeWindow, uint160 budget, uint96 initialWindowStartTime, bytes32[] targetProviders) rule, tuple(uint128 amountUsed, uint128 currentTimeWindowStartTime) usage)[])'
|
|
239
|
+
], provider);
|
|
240
|
+
console.log('Fetching spending rules...');
|
|
241
|
+
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
|
+
});
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
console.error('❌ Test 3 failed:', error);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
exports.ViewSpendingRules = ViewSpendingRules;
|
|
256
|
+
/**
|
|
257
|
+
* Test 4: Withdraw Funds
|
|
258
|
+
*/
|
|
259
|
+
async function WithdrawFunds(sdk, owner, proxyAddress, signFunction) {
|
|
260
|
+
try {
|
|
261
|
+
const withdrawAmount = ethers_1.ethers.parseUnits('50', 18); // Withdraw 50 tokens
|
|
262
|
+
const withdrawRequest = {
|
|
263
|
+
target: proxyAddress,
|
|
264
|
+
value: 0n,
|
|
265
|
+
callData: ethers_1.ethers.Interface.from([
|
|
266
|
+
'function withdrawFunds(address token, uint256 amount)'
|
|
267
|
+
]).encodeFunctionData('withdrawFunds', [
|
|
268
|
+
ADDRESSES.SETTLEMENT_TOKEN,
|
|
269
|
+
withdrawAmount // amount to withdraw
|
|
270
|
+
])
|
|
271
|
+
};
|
|
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);
|
|
276
|
+
if (result.status.status === 'success') {
|
|
277
|
+
console.log('✅ Funds withdrawn successfully!');
|
|
278
|
+
console.log('Transaction hash:', result.status.transactionHash);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
console.log('❌ Withdrawal failed:', result.status.reason);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
console.error('❌ Test 4 failed:', error);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
exports.WithdrawFunds = WithdrawFunds;
|
|
289
|
+
/**
|
|
290
|
+
* Test 5: Check Token Balance (Read-only)
|
|
291
|
+
*/
|
|
292
|
+
async function CheckTokenBalance(sdk, proxyAddress) {
|
|
293
|
+
try {
|
|
294
|
+
const provider = new ethers_1.ethers.JsonRpcProvider('https://rpc-testnet.gokite.ai');
|
|
295
|
+
const tokenContract = new ethers_1.ethers.Contract(ADDRESSES.SETTLEMENT_TOKEN, [
|
|
296
|
+
'function balanceOf(address account) view returns (uint256)',
|
|
297
|
+
'function symbol() view returns (string)',
|
|
298
|
+
'function decimals() view returns (uint8)'
|
|
299
|
+
], provider);
|
|
300
|
+
console.log('Checking token balance...');
|
|
301
|
+
const [balance, symbol, decimals] = await Promise.all([
|
|
302
|
+
tokenContract.balanceOf(proxyAddress),
|
|
303
|
+
tokenContract.symbol(),
|
|
304
|
+
tokenContract.decimals()
|
|
305
|
+
]);
|
|
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}`);
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
console.error('❌ Test 5 failed:', error);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
exports.CheckTokenBalance = CheckTokenBalance;
|
|
316
|
+
/**
|
|
317
|
+
* Legacy example for basic AA operations
|
|
318
|
+
*/
|
|
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
|
+
};
|
|
337
|
+
try {
|
|
338
|
+
const result = await sdk.sendUserOperationAndWait(owner, sendEthRequest, signFunction);
|
|
339
|
+
if (result.status.status === 'success') {
|
|
340
|
+
console.log('✅ ETH transfer successful!');
|
|
341
|
+
console.log('Transaction hash:', result.status.transactionHash);
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
console.log('❌ ETH transfer failed:', result.status.reason);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
console.error('❌ Basic example failed:', error);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
exports.basicExample = basicExample;
|
|
352
|
+
/**
|
|
353
|
+
* Parse ContractCreated event from transaction logs to get deployed proxy address
|
|
354
|
+
* Event: ContractCreated(address indexed contractAddress)
|
|
355
|
+
*/
|
|
356
|
+
async function parseContractCreatedEvent(transactionHash) {
|
|
357
|
+
try {
|
|
358
|
+
const provider = new ethers_1.ethers.JsonRpcProvider('https://rpc-testnet.gokite.ai');
|
|
359
|
+
const receipt = await provider.getTransactionReceipt(transactionHash);
|
|
360
|
+
if (!receipt) {
|
|
361
|
+
console.error('Transaction receipt not found');
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
// ContractCreated event signature: ContractCreated(address indexed contractAddress)
|
|
365
|
+
const contractCreatedEventSignature = ethers_1.ethers.id('ContractCreated(address)');
|
|
366
|
+
console.log('Parsing transaction logs...');
|
|
367
|
+
console.log(`Total logs: ${receipt.logs.length}`);
|
|
368
|
+
for (const log of receipt.logs) {
|
|
369
|
+
// Check if this log matches the ContractCreated event
|
|
370
|
+
if (log.topics[0] === contractCreatedEventSignature) {
|
|
371
|
+
// The first topic is the event signature
|
|
372
|
+
// The second topic is the indexed contractAddress
|
|
373
|
+
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
|
+
return contractAddress;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
console.log('No ContractCreated event found in transaction logs');
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
catch (error) {
|
|
384
|
+
console.error('Error parsing ContractCreated event:', error);
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
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!');
|
|
394
|
+
}
|
|
395
|
+
// Legacy export for backwards compatibility
|
|
396
|
+
exports.example = basicExample;
|
|
397
|
+
main().catch(console.error);
|