@dag-kit/kit 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/dist/esm/clients/actions/contract.js +42 -0
- package/dist/esm/clients/actions/example.js +211 -0
- package/dist/esm/clients/actions/example2.js +47 -0
- package/dist/esm/clients/actions/index.js +1 -0
- package/dist/esm/clients/actions/main.js +266 -0
- package/dist/esm/clients/actions/test.js +1 -0
- package/dist/esm/clients/chains.js +14 -0
- package/dist/esm/clients/types.js +1 -0
- package/dist/esm/exports/index.js +1 -0
- package/dist/esm/script.js +1 -0
- package/package.json +67 -0
- package/src/clients/actions/contract.ts +42 -0
- package/src/clients/actions/example.ts +252 -0
- package/src/clients/actions/example2.ts +57 -0
- package/src/clients/actions/index.ts +0 -0
- package/src/clients/actions/main.ts +376 -0
- package/src/clients/actions/test.ts +0 -0
- package/src/clients/chains.ts +16 -0
- package/src/clients/types.ts +44 -0
- package/src/exports/index.ts +8 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
// ==============================================================================
|
|
2
|
+
// DAG AA SDK - BlockDAG Account Abstraction SDK
|
|
3
|
+
// Inspired by Alchemy AA SDK
|
|
4
|
+
// ==============================================================================
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
createPublicClient,
|
|
8
|
+
createWalletClient,
|
|
9
|
+
http,
|
|
10
|
+
type Chain,
|
|
11
|
+
type Transport,
|
|
12
|
+
type Account,
|
|
13
|
+
type Hash,
|
|
14
|
+
type Address,
|
|
15
|
+
encodeFunctionData,
|
|
16
|
+
parseEther,
|
|
17
|
+
} from "viem";
|
|
18
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
19
|
+
import { toSimpleSmartAccount } from "permissionless/accounts";
|
|
20
|
+
import { createPimlicoClient } from "permissionless/clients/pimlico";
|
|
21
|
+
import { entryPoint06Address } from "viem/account-abstraction";
|
|
22
|
+
import { createSmartAccountClient } from "permissionless";
|
|
23
|
+
import {
|
|
24
|
+
DagAAConfig,
|
|
25
|
+
SmartAccountConfig,
|
|
26
|
+
SendUserOperationParams,
|
|
27
|
+
UserOperationReceipt,
|
|
28
|
+
} from "../types";
|
|
29
|
+
|
|
30
|
+
// ==============================================================================
|
|
31
|
+
// Main SDK Class
|
|
32
|
+
// ==============================================================================
|
|
33
|
+
|
|
34
|
+
export class DagAAClient {
|
|
35
|
+
private config: DagAAConfig;
|
|
36
|
+
private publicClient: ReturnType<typeof createPublicClient>;
|
|
37
|
+
private walletClient: ReturnType<typeof createWalletClient>;
|
|
38
|
+
private bundlerClient: ReturnType<typeof createPimlicoClient> | null = null;
|
|
39
|
+
private smartAccount: any | null = null;
|
|
40
|
+
private smartAccountClient: ReturnType<
|
|
41
|
+
typeof createSmartAccountClient
|
|
42
|
+
> | null = null;
|
|
43
|
+
|
|
44
|
+
constructor(config: DagAAConfig) {
|
|
45
|
+
this.config = {
|
|
46
|
+
...config,
|
|
47
|
+
entryPointAddress: config.entryPointAddress || entryPoint06Address,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
this.publicClient = createPublicClient({
|
|
51
|
+
chain: config.chain,
|
|
52
|
+
transport: http(config.rpcUrl),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
this.walletClient = createWalletClient({
|
|
56
|
+
chain: config.chain,
|
|
57
|
+
transport: http(config.rpcUrl),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ==============================================================================
|
|
62
|
+
// Smart Account Management
|
|
63
|
+
// ==============================================================================
|
|
64
|
+
|
|
65
|
+
async connectSmartAccount(
|
|
66
|
+
accountConfig: SmartAccountConfig
|
|
67
|
+
): Promise<Address> {
|
|
68
|
+
const owner = privateKeyToAccount(accountConfig.owner);
|
|
69
|
+
|
|
70
|
+
const signingClient = createWalletClient({
|
|
71
|
+
account: owner,
|
|
72
|
+
chain: this.config.chain,
|
|
73
|
+
transport: http(this.config.rpcUrl),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (accountConfig.accountAddress) {
|
|
77
|
+
// Use existing account
|
|
78
|
+
this.smartAccount = await toSimpleSmartAccount({
|
|
79
|
+
client: signingClient,
|
|
80
|
+
owner: owner,
|
|
81
|
+
factoryAddress: this.config.factoryAddress,
|
|
82
|
+
entryPoint: {
|
|
83
|
+
address: this.config.entryPointAddress!,
|
|
84
|
+
version: "0.6",
|
|
85
|
+
},
|
|
86
|
+
address: accountConfig.accountAddress,
|
|
87
|
+
});
|
|
88
|
+
} else {
|
|
89
|
+
// Create new account
|
|
90
|
+
this.smartAccount = await toSimpleSmartAccount({
|
|
91
|
+
client: signingClient,
|
|
92
|
+
owner: owner,
|
|
93
|
+
factoryAddress: this.config.factoryAddress,
|
|
94
|
+
entryPoint: {
|
|
95
|
+
address: this.config.entryPointAddress!,
|
|
96
|
+
version: "0.6",
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Create bundler client
|
|
102
|
+
this.bundlerClient = createPimlicoClient({
|
|
103
|
+
transport: http(this.config.bundlerUrl),
|
|
104
|
+
entryPoint: {
|
|
105
|
+
address: this.config.entryPointAddress!,
|
|
106
|
+
version: "0.6",
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Create smart account client
|
|
111
|
+
this.smartAccountClient = createSmartAccountClient({
|
|
112
|
+
bundlerTransport: http(this.config.bundlerUrl),
|
|
113
|
+
chain: this.config.chain,
|
|
114
|
+
account: this.smartAccount,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
console.log(`✅ Connected to smart account: ${this.smartAccount.address}`);
|
|
118
|
+
return this.smartAccount.address;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ==============================================================================
|
|
122
|
+
// Account Information
|
|
123
|
+
// ==============================================================================
|
|
124
|
+
|
|
125
|
+
getAddress(): Address {
|
|
126
|
+
if (!this.smartAccount) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
"Smart account not connected. Call connectSmartAccount() first."
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
return this.smartAccount.address;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async getBalance(): Promise<bigint> {
|
|
135
|
+
if (!this.smartAccount) {
|
|
136
|
+
throw new Error("Smart account not connected");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return await this.publicClient.getBalance({
|
|
140
|
+
address: this.smartAccount.address,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async isDeployed(): Promise<boolean> {
|
|
145
|
+
if (!this.smartAccount) {
|
|
146
|
+
throw new Error("Smart account not connected");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const code = await this.publicClient.getCode({
|
|
150
|
+
address: this.smartAccount.address,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
return code !== undefined && code !== "0x";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async getNonce(): Promise<bigint> {
|
|
157
|
+
if (!this.smartAccount) {
|
|
158
|
+
throw new Error("Smart account not connected");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return await this.publicClient.readContract({
|
|
162
|
+
address: this.config.entryPointAddress!,
|
|
163
|
+
abi: [
|
|
164
|
+
{
|
|
165
|
+
name: "getNonce",
|
|
166
|
+
type: "function",
|
|
167
|
+
stateMutability: "view",
|
|
168
|
+
inputs: [
|
|
169
|
+
{ name: "sender", type: "address" },
|
|
170
|
+
{ name: "key", type: "uint192" },
|
|
171
|
+
],
|
|
172
|
+
outputs: [{ name: "nonce", type: "uint256" }],
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
functionName: "getNonce",
|
|
176
|
+
args: [this.smartAccount.address, 0n],
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ==============================================================================
|
|
181
|
+
// Send UserOperations
|
|
182
|
+
// ==============================================================================
|
|
183
|
+
|
|
184
|
+
async sendUserOperation(params: SendUserOperationParams): Promise<Hash> {
|
|
185
|
+
if (!this.smartAccountClient) {
|
|
186
|
+
throw new Error("Smart account not connected");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const {
|
|
190
|
+
target,
|
|
191
|
+
data = "0x",
|
|
192
|
+
value = 0n,
|
|
193
|
+
maxFeePerGas,
|
|
194
|
+
maxPriorityFeePerGas,
|
|
195
|
+
callGasLimit = 150000n,
|
|
196
|
+
verificationGasLimit = 300000n,
|
|
197
|
+
preVerificationGas = 100000n,
|
|
198
|
+
} = params;
|
|
199
|
+
|
|
200
|
+
// Get gas prices if not provided
|
|
201
|
+
let gasPrices = {
|
|
202
|
+
maxFeePerGas: maxFeePerGas,
|
|
203
|
+
maxPriorityFeePerGas: maxPriorityFeePerGas,
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
if (!maxFeePerGas || !maxPriorityFeePerGas) {
|
|
207
|
+
const estimatedGas = await this.bundlerClient!.getUserOperationGasPrice();
|
|
208
|
+
gasPrices = {
|
|
209
|
+
maxFeePerGas: maxFeePerGas || estimatedGas.fast.maxFeePerGas,
|
|
210
|
+
maxPriorityFeePerGas:
|
|
211
|
+
maxPriorityFeePerGas || estimatedGas.fast.maxPriorityFeePerGas,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
console.log("Sending UserOperation...");
|
|
216
|
+
console.log(` Target: ${target}`);
|
|
217
|
+
console.log(` Value: ${value}`);
|
|
218
|
+
console.log(
|
|
219
|
+
` Gas: ${gasPrices.maxFeePerGas} / ${gasPrices.maxPriorityFeePerGas}`
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
const userOpHash = await this.smartAccountClient.sendTransaction({
|
|
223
|
+
calls: [
|
|
224
|
+
{
|
|
225
|
+
to: target,
|
|
226
|
+
value: value,
|
|
227
|
+
data: data,
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
maxFeePerGas: gasPrices.maxFeePerGas,
|
|
231
|
+
maxPriorityFeePerGas: gasPrices.maxPriorityFeePerGas,
|
|
232
|
+
callGasLimit,
|
|
233
|
+
verificationGasLimit,
|
|
234
|
+
preVerificationGas,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
console.log(`✅ UserOperation sent: ${userOpHash}`);
|
|
238
|
+
return userOpHash;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ==============================================================================
|
|
242
|
+
// Contract Interactions
|
|
243
|
+
// ==============================================================================
|
|
244
|
+
|
|
245
|
+
async writeContract(params: {
|
|
246
|
+
address: Address;
|
|
247
|
+
abi: any[];
|
|
248
|
+
functionName: string;
|
|
249
|
+
args?: any[];
|
|
250
|
+
value?: bigint;
|
|
251
|
+
maxFeePerGas?: bigint;
|
|
252
|
+
maxPriorityFeePerGas?: bigint;
|
|
253
|
+
}): Promise<Hash> {
|
|
254
|
+
const { address, abi, functionName, args = [], value = 0n } = params;
|
|
255
|
+
|
|
256
|
+
const data = encodeFunctionData({
|
|
257
|
+
abi,
|
|
258
|
+
functionName,
|
|
259
|
+
args,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
return await this.sendUserOperation({
|
|
263
|
+
target: address,
|
|
264
|
+
data,
|
|
265
|
+
value,
|
|
266
|
+
maxFeePerGas: params.maxFeePerGas,
|
|
267
|
+
maxPriorityFeePerGas: params.maxPriorityFeePerGas,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async readContract(params: {
|
|
272
|
+
address: Address;
|
|
273
|
+
abi: any[];
|
|
274
|
+
functionName: string;
|
|
275
|
+
args?: any[];
|
|
276
|
+
}): Promise<any> {
|
|
277
|
+
return await this.publicClient.readContract({
|
|
278
|
+
address: params.address,
|
|
279
|
+
abi: params.abi,
|
|
280
|
+
functionName: params.functionName,
|
|
281
|
+
args: params.args || [],
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// ==============================================================================
|
|
286
|
+
// Utilities
|
|
287
|
+
// ==============================================================================
|
|
288
|
+
|
|
289
|
+
async waitForUserOperationReceipt(
|
|
290
|
+
userOpHash: Hash,
|
|
291
|
+
timeout: number = 30000
|
|
292
|
+
): Promise<UserOperationReceipt> {
|
|
293
|
+
console.log(`Waiting for UserOperation receipt...`);
|
|
294
|
+
|
|
295
|
+
const startTime = Date.now();
|
|
296
|
+
|
|
297
|
+
while (Date.now() - startTime < timeout) {
|
|
298
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
299
|
+
|
|
300
|
+
// In a real implementation, you'd query the bundler for receipt
|
|
301
|
+
// For now, we'll return a basic receipt structure
|
|
302
|
+
console.log("Checking for receipt...");
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
userOpHash,
|
|
307
|
+
success: true,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async fundAccount(
|
|
312
|
+
amount: bigint,
|
|
313
|
+
fromPrivateKey: `0x${string}`
|
|
314
|
+
): Promise<Hash> {
|
|
315
|
+
if (!this.smartAccount) {
|
|
316
|
+
throw new Error("Smart account not connected");
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const signer = privateKeyToAccount(fromPrivateKey);
|
|
320
|
+
const client = createWalletClient({
|
|
321
|
+
account: signer,
|
|
322
|
+
chain: this.config.chain,
|
|
323
|
+
transport: http(this.config.rpcUrl),
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
console.log(`Funding account with ${amount} wei...`);
|
|
327
|
+
|
|
328
|
+
const hash = await client.sendTransaction({
|
|
329
|
+
to: this.smartAccount.address,
|
|
330
|
+
value: amount,
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
console.log(`✅ Funded: ${hash}`);
|
|
334
|
+
return hash;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ==============================================================================
|
|
338
|
+
// Batch Operations
|
|
339
|
+
// ==============================================================================
|
|
340
|
+
|
|
341
|
+
async sendBatchUserOperations(
|
|
342
|
+
operations: SendUserOperationParams[]
|
|
343
|
+
): Promise<Hash[]> {
|
|
344
|
+
const results: Hash[] = [];
|
|
345
|
+
|
|
346
|
+
for (const op of operations) {
|
|
347
|
+
const hash = await this.sendUserOperation(op);
|
|
348
|
+
results.push(hash);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return results;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// ==============================================================================
|
|
356
|
+
// Helper Functions
|
|
357
|
+
// ==============================================================================
|
|
358
|
+
|
|
359
|
+
export function createDagAAClient(config: DagAAConfig): DagAAClient {
|
|
360
|
+
return new DagAAClient(config);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export function parseDAG(amount: string): bigint {
|
|
364
|
+
return parseEther(amount);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// ==============================================================================
|
|
368
|
+
// Export Types
|
|
369
|
+
// ==============================================================================
|
|
370
|
+
|
|
371
|
+
// export type {
|
|
372
|
+
// DagAAConfig,
|
|
373
|
+
// SmartAccountConfig,
|
|
374
|
+
// SendUserOperationParams,
|
|
375
|
+
// UserOperationReceipt,
|
|
376
|
+
// };
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineChain } from "viem";
|
|
2
|
+
|
|
3
|
+
const awakening_ = defineChain({
|
|
4
|
+
id: 1043,
|
|
5
|
+
name: "Awakening Testnet",
|
|
6
|
+
nativeCurrency: { decimals: 18, name: "Dag", symbol: "DAG" },
|
|
7
|
+
rpcUrls: { default: { http: ["https://public-bdag.nownodes.io"] } },
|
|
8
|
+
blockExplorers: {
|
|
9
|
+
default: { name: "Explorer", url: "https://awakening.bdagscan.com/" },
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const awakening = {
|
|
14
|
+
bundler_rpc: "http://0.0.0.0:3000/",
|
|
15
|
+
chain_config: awakening_,
|
|
16
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createPublicClient,
|
|
3
|
+
createWalletClient,
|
|
4
|
+
http,
|
|
5
|
+
type Chain,
|
|
6
|
+
type Transport,
|
|
7
|
+
type Account,
|
|
8
|
+
type Hash,
|
|
9
|
+
type Address,
|
|
10
|
+
encodeFunctionData,
|
|
11
|
+
parseEther,
|
|
12
|
+
} from "viem";
|
|
13
|
+
|
|
14
|
+
export interface DagAAConfig {
|
|
15
|
+
chain: Chain;
|
|
16
|
+
rpcUrl: string;
|
|
17
|
+
bundlerUrl: string;
|
|
18
|
+
factoryAddress: Address;
|
|
19
|
+
entryPointAddress?: Address;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SmartAccountConfig {
|
|
23
|
+
owner: `0x${string}`;
|
|
24
|
+
accountAddress?: Address;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface SendUserOperationParams {
|
|
28
|
+
target: Address;
|
|
29
|
+
data?: `0x${string}`;
|
|
30
|
+
value?: bigint;
|
|
31
|
+
maxFeePerGas?: bigint;
|
|
32
|
+
maxPriorityFeePerGas?: bigint;
|
|
33
|
+
callGasLimit?: bigint;
|
|
34
|
+
verificationGasLimit?: bigint;
|
|
35
|
+
preVerificationGas?: bigint;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface UserOperationReceipt {
|
|
39
|
+
userOpHash: Hash;
|
|
40
|
+
transactionHash?: Hash;
|
|
41
|
+
success: boolean;
|
|
42
|
+
blockNumber?: bigint;
|
|
43
|
+
blockHash?: Hash;
|
|
44
|
+
}
|