@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 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
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.1.7",
6
+ "version": "0.2.0",
7
7
  "description": "SDK for ERC-4337 Gasless Transfers",
8
8
  "main": "./dist/index.js",
9
9
  "module": "./dist/index.mjs",
@@ -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;