@1llet.xyz/erc4337-gasless-sdk 0.1.7 → 0.2.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 +33 -0
- package/package.json +1 -1
- package/src/AccountAbstraction.ts +97 -1
package/README.md
CHANGED
|
@@ -143,6 +143,39 @@ const address = await aa.getSmartAccountAddress(ownerAddress);
|
|
|
143
143
|
const receipt = await aa.deployAccount();
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
+
### Simplified Transactions (v0.2.0+)
|
|
147
|
+
|
|
148
|
+
Send transactions without manually building, signing, and waiting.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// 1. Send ETH or Call Contract (Single)
|
|
152
|
+
const receipt = await aa.sendTransaction({
|
|
153
|
+
target: "0x123...",
|
|
154
|
+
value: 1000000000000000000n, // 1 ETH
|
|
155
|
+
data: "0x..." // Optional callData
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// 2. Send Multiple Transactions (Batch)
|
|
159
|
+
// Great for approving + swapping, or multiple transfers
|
|
160
|
+
const receipt = await aa.sendBatchTransaction([
|
|
161
|
+
{ target: "0xToken...", data: encodeApproveData },
|
|
162
|
+
{ target: "0xSwap...", data: encodeSwapData }
|
|
163
|
+
]);
|
|
164
|
+
|
|
165
|
+
// 3. Transfer ERC-20 Tokens (Helper)
|
|
166
|
+
// Automatically encodes the transfer call
|
|
167
|
+
const receipt = await aa.transfer(
|
|
168
|
+
usdcAddress,
|
|
169
|
+
recipientAddress,
|
|
170
|
+
1000000n // 1 USDC
|
|
171
|
+
);
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Error Decoding
|
|
175
|
+
The SDK now automatically tries to decode cryptic "0x..." errors from the EntryPoint into readable messages like:
|
|
176
|
+
- `Smart Account Error: Transfer amount exceeds balance`
|
|
177
|
+
- `Smart Account: Native transfer failed`
|
|
178
|
+
|
|
146
179
|
### Simplified Approvals
|
|
147
180
|
|
|
148
181
|
```typescript
|
package/package.json
CHANGED
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
type Address,
|
|
8
8
|
type Hash,
|
|
9
9
|
type Hex,
|
|
10
|
-
type PublicClient
|
|
10
|
+
type PublicClient,
|
|
11
|
+
decodeErrorResult
|
|
11
12
|
} from "viem";
|
|
12
13
|
import {
|
|
13
14
|
factoryAbi,
|
|
@@ -452,6 +453,80 @@ export class AccountAbstraction {
|
|
|
452
453
|
return await this.waitForUserOperation(hash);
|
|
453
454
|
}
|
|
454
455
|
|
|
456
|
+
/**
|
|
457
|
+
* Send a single transaction via the Smart Account
|
|
458
|
+
* Abstracts: Build -> Sign -> Send -> Wait
|
|
459
|
+
*/
|
|
460
|
+
async sendTransaction(
|
|
461
|
+
tx: { target: Address; value?: bigint; data?: Hex }
|
|
462
|
+
): Promise<UserOpReceipt> {
|
|
463
|
+
return this.sendBatchTransaction([tx]);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Send multiple transactions via the Smart Account (Batched)
|
|
468
|
+
* Abstracts: Build -> Sign -> Send -> Wait
|
|
469
|
+
*/
|
|
470
|
+
async sendBatchTransaction(
|
|
471
|
+
txs: { target: Address; value?: bigint; data?: Hex }[]
|
|
472
|
+
): Promise<UserOpReceipt> {
|
|
473
|
+
// Normalize input (default value to 0, data to 0x)
|
|
474
|
+
const transactions = txs.map(tx => ({
|
|
475
|
+
target: tx.target,
|
|
476
|
+
value: tx.value ?? 0n,
|
|
477
|
+
data: tx.data ?? "0x"
|
|
478
|
+
}));
|
|
479
|
+
|
|
480
|
+
try {
|
|
481
|
+
const userOp = await this.buildUserOperationBatch(transactions);
|
|
482
|
+
const signed = await this.signUserOperation(userOp);
|
|
483
|
+
const hash = await this.sendUserOperation(signed);
|
|
484
|
+
return await this.waitForUserOperation(hash);
|
|
485
|
+
} catch (error) {
|
|
486
|
+
throw this.decodeError(error);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Try to decode meaningful errors from RPC or Revert data
|
|
492
|
+
*/
|
|
493
|
+
private decodeError(error: any): Error {
|
|
494
|
+
const msg = error?.message || "";
|
|
495
|
+
|
|
496
|
+
// 1. Try to find hex data in the error message (UserOp Revert)
|
|
497
|
+
// Look for 0x... in "data": "0x..." or in the message itself
|
|
498
|
+
const hexMatch = msg.match(/(0x[0-9a-fA-F]+)/);
|
|
499
|
+
|
|
500
|
+
if (hexMatch) {
|
|
501
|
+
try {
|
|
502
|
+
// Try decoding as standard Error(string)
|
|
503
|
+
const decoded = decodeErrorResult({
|
|
504
|
+
abi: [
|
|
505
|
+
{
|
|
506
|
+
inputs: [{ name: "message", type: "string" }],
|
|
507
|
+
name: "Error",
|
|
508
|
+
type: "error"
|
|
509
|
+
},
|
|
510
|
+
// Add common EntryPoint errors if known, but generic Reverts are most common
|
|
511
|
+
],
|
|
512
|
+
data: hexMatch[0] as Hex
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
if (decoded.errorName === "Error") {
|
|
516
|
+
return new Error(`Smart Account Error: ${decoded.args[0]}`);
|
|
517
|
+
}
|
|
518
|
+
} catch (e) {
|
|
519
|
+
// Failed to decode, stick to original
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// 2. Common EntryPoint error mapping (simplified)
|
|
524
|
+
if (msg.includes("AA21")) return new Error("Smart Account: Native transfer failed (ETH missing?)");
|
|
525
|
+
if (msg.includes("AA25")) return new Error("Smart Account: Invalid account nonce");
|
|
526
|
+
|
|
527
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
528
|
+
}
|
|
529
|
+
|
|
455
530
|
/**
|
|
456
531
|
* Approve a token for the Smart Account (EOA -> Token -> Smart Account)
|
|
457
532
|
* Checks for gas sponsorship (Relayer funding) if needed.
|
|
@@ -495,6 +570,27 @@ export class AccountAbstraction {
|
|
|
495
570
|
return "NOT_NEEDED";
|
|
496
571
|
}
|
|
497
572
|
|
|
573
|
+
/**
|
|
574
|
+
* Transfer ERC-20 tokens from the Smart Account to a recipient
|
|
575
|
+
*/
|
|
576
|
+
async transfer(
|
|
577
|
+
token: Address,
|
|
578
|
+
recipient: Address,
|
|
579
|
+
amount: bigint
|
|
580
|
+
): Promise<UserOpReceipt> {
|
|
581
|
+
const data = encodeFunctionData({
|
|
582
|
+
abi: erc20Abi,
|
|
583
|
+
functionName: "transfer",
|
|
584
|
+
args: [recipient, amount]
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
return this.sendTransaction({
|
|
588
|
+
target: token,
|
|
589
|
+
value: 0n,
|
|
590
|
+
data
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
|
|
498
594
|
// Getters
|
|
499
595
|
getOwner(): Address | null {
|
|
500
596
|
return this.owner;
|