@tapforce/pod-bridge-sdk 1.2.4 → 2.0.1

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
@@ -1,26 +1,27 @@
1
1
  # Pod Bridge SDK
2
2
 
3
- TypeScript SDK for bridging ERC20 tokens between POD and EVM chains (e.g., Sepolia/ETH).
3
+ TypeScript SDK for bridging tokens between POD and EVM chains (e.g., ETH Mainnet).
4
4
 
5
5
  ## Architecture
6
6
 
7
7
  ```
8
- ETH Pod: Deposit on ETH, AUTO-CLAIM on Pod (no claim TX needed)
9
- Pod ETH: Deposit on Pod, claim on ETH with aggregated validator signatures
8
+ ETH -> Pod: Deposit on ETH, AUTO-CLAIM on Pod (no claim TX needed)
9
+ Pod -> ETH: Deposit on Pod, claim on ETH with proof from pod_getBridgeClaimProof RPC
10
10
  ```
11
11
 
12
12
  **Key points:**
13
- - Only ERC20 tokens supported (wrap ETH to WETH first)
14
- - `Deposit.id` on source chain = `Claim.id` on destination chain (for tracking)
15
- - Token addresses differ between chains
13
+ - ERC20 and native token bridging supported
14
+ - Token addresses differ between chains (e.g., USDC on ETH maps to native `0xEeee...EEeE` on Pod)
15
+ - Use ETH-side decimals for amounts (e.g., `1e6` for 1 USDC, not `1e18`)
16
+ - Pod transactions require EIP-1559 (type 2) gas params, not legacy `gasPrice`
16
17
 
17
18
  ## Features
18
19
 
19
- - **Bridge ERC20 Deposits**: Deposit tokens to the bridge
20
- - **Track Bridge Requests**: Query deposits sent/received by any address
20
+ - **Bridge Deposits**: Deposit ERC20 or native tokens to the bridge
21
+ - **Claim with Proof**: Claim on ETH using `pod_getBridgeClaimProof` RPC
22
+ - **Track Bridge Requests**: Query deposits sent/received by any address
21
23
  - **Claim Status Tracking**: Monitor claim status and finality
22
24
  - **Transaction Building**: Generate unsigned transactions ready for signing
23
- - **Type-Safe**: Full TypeScript support
24
25
 
25
26
  ## Installation
26
27
 
@@ -35,12 +36,13 @@ pnpm add @tapforce/pod-bridge-sdk
35
36
  ## Quick Start
36
37
 
37
38
  ```typescript
38
- import {
39
+ import {
39
40
  SourceChainToPodActionClient,
40
41
  PodToSourceChainActionClient,
41
42
  PodBridgeTrackerClient,
42
- PodBridgeConfig,
43
- BRIDGE_ABI
43
+ getBridgeClaimProof,
44
+ SOURCE_CHAIN_BRIDGE_ABI,
45
+ POD_BRIDGE_ABI,
44
46
  } from '@tapforce/pod-bridge-sdk';
45
47
  ```
46
48
 
@@ -53,10 +55,10 @@ import { PodBridgeActionsClientConfig } from '@tapforce/pod-bridge-sdk';
53
55
 
54
56
  const actionConfig: PodBridgeActionsClientConfig = {
55
57
  sourceChain: {
56
- contractAddress: '0x...' // Bridge contract on ETH/Sepolia
58
+ contractAddress: '0x...' // BridgeDepositWithdraw on ETH
57
59
  },
58
60
  pod: {
59
- contractAddress: '0x...' // Bridge contract on Pod
61
+ contractAddress: '0x0000000000000000000000000000000000B41D9E' // BridgeMintBurn on Pod
60
62
  }
61
63
  };
62
64
  ```
@@ -69,13 +71,13 @@ import { ethers } from 'ethers';
69
71
 
70
72
  const trackerConfig: PodBridgeConfig = {
71
73
  sourceChain: {
72
- provider: new ethers.JsonRpcProvider('https://sepolia.infura.io/v3/YOUR_KEY'),
74
+ provider: new ethers.JsonRpcProvider('https://eth-mainnet.rpc.example'),
73
75
  contractAddress: '0x...',
74
- deploymentBlock: 9502541 // Optional: avoids indexing empty blocks
76
+ deploymentBlock: 12345678 // Optional: avoids indexing empty blocks
75
77
  },
76
78
  pod: {
77
79
  provider: new ethers.JsonRpcProvider('https://rpc.pod.network'),
78
- contractAddress: '0x...',
80
+ contractAddress: '0x0000000000000000000000000000000000B41D9E',
79
81
  deploymentBlock: 0
80
82
  }
81
83
  };
@@ -83,76 +85,71 @@ const trackerConfig: PodBridgeConfig = {
83
85
 
84
86
  ## Usage
85
87
 
86
- ### ETH Pod (Auto-claim)
88
+ ### ETH -> Pod (Auto-claim)
87
89
 
88
- Deposits on ETH are automatically claimed on Pod after block finalization (~15 min on Sepolia).
90
+ Deposits on ETH are automatically claimed on Pod after block finalization.
89
91
 
90
92
  ```typescript
91
93
  const client = new SourceChainToPodActionClient(actionConfig);
92
94
 
93
- // Create deposit transaction
95
+ // Create deposit transaction (with optional permit for gasless approval)
94
96
  const depositTx = client.deposit({
95
- token: '0xWETH_ADDRESS', // ERC20 token on ETH
96
- amount: ethers.parseEther('1'),
97
- destinationWalletAddress: '0x...', // Recipient on Pod
98
- from: '0x...' // Optional
97
+ token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on ETH
98
+ amount: ethers.parseUnits('1', 6), // 1 USDC (use ETH-side decimals)
99
+ destinationWalletAddress: '0x...',
100
+ from: '0x...',
101
+ // permit: '0x...' // Optional: ERC20 permit bytes
99
102
  });
100
103
 
101
- // Send transaction
104
+ // Don't forget to approve the bridge contract first for ERC20 tokens
102
105
  const tx = await signer.sendTransaction(depositTx);
103
106
  const receipt = await tx.wait();
104
107
 
105
108
  // No claim needed - balance auto-credited on Pod after finalization
106
109
  ```
107
110
 
108
- ### Pod ETH (Manual claim with signatures)
111
+ ### Pod -> ETH (Claim with proof)
109
112
 
110
- Deposits on Pod require manual claim on ETH with aggregated validator signatures.
113
+ Deposits on Pod require claiming on ETH with a proof from `pod_getBridgeClaimProof`.
111
114
 
112
115
  ```typescript
113
- import {
116
+ import {
114
117
  PodToSourceChainActionClient,
115
- extractAggregatedSignaturesWithValidators
118
+ getBridgeClaimProof,
119
+ ClaimProofData,
116
120
  } from '@tapforce/pod-bridge-sdk';
117
121
 
118
122
  const client = new PodToSourceChainActionClient(actionConfig);
119
123
 
120
124
  // Step 1: Deposit on Pod
121
125
  const depositTx = client.deposit({
122
- token: '0xPOD_TOKEN_ADDRESS', // ERC20 token on Pod
123
- amount: ethers.parseEther('1'),
124
- destinationWalletAddress: '0x...', // Recipient on ETH
125
- from: '0x...'
126
+ token: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // Native token on Pod
127
+ amount: ethers.parseUnits('1', 6), // Use ETH-side decimals (1 USDC = 1e6)
128
+ destinationWalletAddress: '0x...',
129
+ from: '0x...',
126
130
  });
127
131
 
128
- const tx = await podSigner.sendTransaction(depositTx);
129
- const receipt = await tx.wait();
130
-
131
- // Step 2: Get the receipt with validator signatures
132
- const podReceipt = await podProvider.send('eth_getTransactionReceipt', [tx.hash]);
133
-
134
- // Step 3: Get committee for v-value recovery
135
- const committee = await podProvider.send('pod_getCommittee', {});
132
+ // Pod requires EIP-1559 gas params (all zeros for free transactions)
133
+ const tx = await podSigner.sendTransaction({
134
+ ...depositTx,
135
+ maxFeePerGas: 0n,
136
+ maxPriorityFeePerGas: 0n,
137
+ gasLimit: 0n,
138
+ });
136
139
 
137
- // Step 4: Extract aggregated signatures (65-byte format with correct v-values)
138
- const aggregatedSignatures = extractAggregatedSignaturesWithValidators(
139
- podReceipt,
140
- committee.validators // [[0, "02..."], [1, "03..."], ...] compressed pubkeys
141
- );
140
+ // Step 2: Get claim proof from Pod RPC
141
+ const { proof, auxTxSuffix } = await getBridgeClaimProof(podProvider, tx.hash);
142
142
 
143
- // Step 5: Claim on ETH
144
- const claimTx = client.claim({
145
- claimData: {
146
- ethTokenAddress: '0xETH_TOKEN_ADDRESS', // Token on ETH (different from Pod)
147
- amount: ethers.parseEther('1'),
148
- to: '0x...', // Recipient
149
- committeeEpoch: 0, // Hardcoded for now
150
- aggregatedSignatures, // 65-byte signatures (r,s,v) concatenated
151
- depositTxHash: tx.hash // Deposit TX hash from Pod
152
- },
153
- from: '0x...'
154
- });
143
+ // Step 3: Claim on ETH
144
+ const claimData: ClaimProofData = {
145
+ ethTokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on ETH
146
+ amount: ethers.parseUnits('1', 6), // Must match deposited amount
147
+ to: '0x...',
148
+ proof,
149
+ auxTxSuffix,
150
+ };
155
151
 
152
+ const claimTx = client.claim({ claimData, from: '0x...' });
156
153
  const claim = await ethSigner.sendTransaction(claimTx);
157
154
  ```
158
155
 
@@ -166,22 +163,18 @@ const deposits = await tracker.getAllDepositsFor('0x...');
166
163
 
167
164
  for (const deposit of deposits) {
168
165
  console.log('Request ID:', deposit.requestId);
169
- console.log('Direction:', deposit.deposit.chain === 'sourceChain' ? 'ETH Pod' : 'Pod ETH');
170
- console.log('From:', deposit.deposit.depositor);
171
- console.log('To:', deposit.deposit.destination);
166
+ console.log('Direction:', deposit.deposit.chain === 'sourceChain' ? 'ETH -> Pod' : 'Pod -> ETH');
172
167
  console.log('Token:', deposit.deposit.token);
173
168
  console.log('Amount:', deposit.deposit.amount);
174
- console.log('Claimed:', deposit.isClaimed);
175
- console.log('Claimable:', deposit.isClaimable);
169
+ console.log('Timestamp:', new Date(deposit.deposit.timestamp * 1000).toISOString());
170
+ console.log('Status:', deposit.isClaimed ? 'Claimed' : (deposit.isClaimable ? 'Claimable' : 'Pending'));
176
171
  }
177
172
 
178
- // Get deposits sent by address
173
+ // Get deposits sent/received by address
179
174
  const sent = await tracker.getDepositsSentBy('0x...');
180
-
181
- // Get deposits received by address
182
175
  const received = await tracker.getDepositsReceivedBy('0x...');
183
176
 
184
- // Check if deposit can be claimed (Pod → ETH only)
177
+ // Check if deposit can be claimed
185
178
  const canClaim = await tracker.canBeClaimed(deposit);
186
179
 
187
180
  // Batch check processed status
@@ -192,38 +185,51 @@ const statuses = await tracker.areRequestsProcessed(deposits);
192
185
 
193
186
  ### SourceChainToPodActionClient
194
187
 
195
- For ETH Pod deposits (auto-claim on Pod).
188
+ For ETH -> Pod deposits (auto-claim on Pod).
196
189
 
197
190
  ```typescript
198
- // Deposit ERC20 tokens
199
191
  deposit(args: {
200
192
  token: string;
201
193
  amount: string | bigint;
202
194
  destinationWalletAddress: string;
203
195
  from?: string;
196
+ permit?: string; // Optional ERC20 permit bytes (default: '0x')
204
197
  }): UnsignedTransaction
205
198
  ```
206
199
 
207
200
  ### PodToSourceChainActionClient
208
201
 
209
- For Pod ETH deposits and claims.
202
+ For Pod -> ETH deposits and claims.
210
203
 
211
204
  ```typescript
212
- // Deposit ERC20 tokens on Pod
205
+ // Deposit tokens on Pod
213
206
  deposit(args: {
214
- token: string;
215
- amount: string | bigint;
207
+ token: string; // Use 0xEeee...EEeE for native token
208
+ amount: string | bigint; // Use ETH-side decimals
216
209
  destinationWalletAddress: string;
217
210
  from?: string;
218
211
  }): UnsignedTransaction
219
212
 
220
- // Claim on ETH with aggregated signatures
213
+ // Claim on ETH with proof
221
214
  claim(args: {
222
215
  claimData: ClaimProofData;
223
216
  from?: string;
224
217
  }): UnsignedTransaction
225
218
  ```
226
219
 
220
+ ### getBridgeClaimProof
221
+
222
+ Helper to call `pod_getBridgeClaimProof` RPC and format the result.
223
+
224
+ ```typescript
225
+ import { getBridgeClaimProof } from '@tapforce/pod-bridge-sdk';
226
+
227
+ const { proof, committeeEpoch, auxTxSuffix } = await getBridgeClaimProof(
228
+ podProvider, // ethers.JsonRpcProvider connected to Pod RPC
229
+ depositTxHash // TX hash of the deposit on Pod
230
+ );
231
+ ```
232
+
227
233
  ### PodBridgeTrackerClient
228
234
 
229
235
  ```typescript
@@ -236,12 +242,24 @@ areRequestsProcessed(deposits: BridgeRequest[]): Promise<boolean[]>
236
242
 
237
243
  ## Types
238
244
 
245
+ ### ClaimProofData
246
+
247
+ ```typescript
248
+ interface ClaimProofData {
249
+ ethTokenAddress: string; // Token address on ETH (different from Pod)
250
+ amount: string | bigint; // Must match deposited amount
251
+ to: string; // Recipient address
252
+ proof: string; // Hex bytes from pod_getBridgeClaimProof
253
+ auxTxSuffix: string; // Hex bytes from pod_getBridgeClaimProof
254
+ }
255
+ ```
256
+
239
257
  ### BridgeRequest
240
258
 
241
259
  ```typescript
242
260
  interface BridgeRequest {
243
261
  requestId: string;
244
-
262
+
245
263
  deposit: {
246
264
  chain: 'sourceChain' | 'pod';
247
265
  txHash: string;
@@ -251,9 +269,9 @@ interface BridgeRequest {
251
269
  amount: string;
252
270
  chainId: number;
253
271
  blockNumber: number;
254
- timestamp: number;
272
+ timestamp: number; // Unix timestamp (seconds)
255
273
  };
256
-
274
+
257
275
  claim?: {
258
276
  chain: 'sourceChain' | 'pod';
259
277
  txHash: string;
@@ -262,99 +280,40 @@ interface BridgeRequest {
262
280
  blockNumber: number;
263
281
  timestamp: number;
264
282
  };
265
-
283
+
266
284
  isClaimed: boolean;
267
285
  isClaimable: boolean;
268
286
  }
269
287
  ```
270
288
 
271
- ### ClaimProofData
272
-
273
- ```typescript
274
- interface ClaimProofData {
275
- ethTokenAddress: string; // Token address on ETH (different from Pod)
276
- amount: string | bigint; // Same amount as deposited
277
- to: string; // Recipient address
278
- committeeEpoch: number; // Hardcoded to 0 for now
279
- aggregatedSignatures: string; // Concatenated 65-byte ECDSA signatures (r,s,v)
280
- depositTxHash: string; // Deposit TX hash from Pod
281
- }
282
- ```
283
-
284
- ### Signature Recovery Helpers
285
-
286
- Pod returns DER-encoded 64-byte signatures without the parity bit (v), but the ETH contract requires 65-byte (r,s,v) format.
287
- The SDK handles this by trying both v values (27/28) and verifying against the committee's validator public keys.
288
-
289
- ```typescript
290
- import {
291
- extractAggregatedSignaturesWithValidators,
292
- extractAggregatedSignatures,
293
- parseDerSignature,
294
- addressFromPublicKey,
295
- recoverSignatureWithoutPubkey
296
- } from '@tapforce/pod-bridge-sdk';
297
-
298
- // Recommended: Extract with validator verification (correct v-values)
299
- const podReceipt = await podProvider.send('eth_getTransactionReceipt', [depositTxHash]);
300
- const committee = await podProvider.send('pod_getCommittee', {});
301
- const aggregatedSignatures = extractAggregatedSignaturesWithValidators(
302
- podReceipt,
303
- committee.validators // [[index, compressedPubKey], ...]
304
- );
305
-
306
- // Alternative: Extract without validator verification (may have wrong v-values)
307
- const sigs = extractAggregatedSignatures(podReceipt);
308
-
309
- // Low-level: Parse DER signature to r,s components
310
- const { r, s } = parseDerSignature(derEncodedSig);
311
-
312
- // Low-level: Recover 65-byte signature without pubkey (tries v=27 first)
313
- const sig65 = recoverSignatureWithoutPubkey(r, s, msgHash);
289
+ ## Events
314
290
 
315
- // Utility: Derive address from uncompressed public key
316
- const address = addressFromPublicKey(uncompressedPubKey);
317
- ```
291
+ The bridge contracts emit different events per chain:
318
292
 
319
- #### Pod Receipt Format
293
+ ```solidity
294
+ // ETH (Source Chain)
295
+ event Deposit(uint256 indexed id, address indexed from, address indexed to, address token, uint256 amount);
296
+ event Claim(bytes32 indexed txHash, address token, address mirrorToken, uint256 amount, address indexed to);
320
297
 
321
- ```typescript
322
- interface PodTransactionReceipt {
323
- // ... standard fields ...
324
- attested_tx: {
325
- hash: string; // Hash signed by validators
326
- committee_epoch: number;
327
- };
328
- signatures: {
329
- "0": string; // DER-encoded signature from validator 0
330
- "1": string; // DER-encoded signature from validator 1
331
- // ...
332
- };
333
- }
298
+ // Pod
299
+ event Deposit(bytes32 indexed id, address indexed from, address indexed to, address token, uint256 amount);
334
300
  ```
335
301
 
336
- #### Committee Format
302
+ ## ABIs
337
303
 
338
- ```typescript
339
- // pod_getCommittee response
340
- {
341
- validators: [
342
- [0, "024ee7..."], // [index, compressed_secp256k1_pubkey]
343
- [1, "025c59..."],
344
- // ...
345
- ],
346
- quorum_size: 3
347
- }
348
- ```
304
+ The SDK exports separate ABIs for each chain:
349
305
 
350
- ## Events
306
+ - `SOURCE_CHAIN_BRIDGE_ABI` - ETH bridge (deposit with permit, claim with proof)
307
+ - `POD_BRIDGE_ABI` - Pod bridge (3-param deposit)
308
+ - `BRIDGE_ABI` - Alias for `SOURCE_CHAIN_BRIDGE_ABI`
351
309
 
352
- The bridge contract emits:
310
+ ## Pod-specific Notes
353
311
 
354
- ```solidity
355
- event Deposit(bytes32 indexed id, address indexed from, address indexed to, address token, uint256 amount);
356
- event Claim(bytes32 indexed id, address indexed to, address token, uint256 amount);
357
- ```
312
+ - Pod system contract address: `0x0000000000000000000000000000000000B41D9E`
313
+ - Pod transactions are free: use `maxFeePerGas: 0, maxPriorityFeePerGas: 0, gasLimit: 0`
314
+ - Must use EIP-1559 (type 2) transactions, not legacy `gasPrice`
315
+ - Pod does NOT need `value` set for native token deposits - the system contract handles balance internally
316
+ - Pod returns `blockNumber` as a Unix timestamp in receipts
358
317
 
359
318
  ## Development
360
319
 
@@ -2,34 +2,33 @@ import { UnsignedTransaction, ClaimProofData, PodBridgeActionsClientConfig } fro
2
2
  /**
3
3
  * PodToSourceChainActionClient - Handles Pod -> ETH bridging
4
4
  *
5
- * New architecture:
6
- * - User deposits ERC20 tokens on Pod
7
- * - Wait for TX receipt from Pod
8
- * - User claims on ETH with aggregated validator signatures
9
- * - Only ERC20 tokens supported (no native tokens)
5
+ * - User deposits tokens on Pod
6
+ * - Call pod_getBridgeClaimProof(depositTxHash) to get proof
7
+ * - User claims on ETH with proof + auxTxSuffix
10
8
  *
11
9
  * Important notes:
12
- * - Token addresses on Pod and ETH are different (user deposits AAAA on Pod, claims BBBB on ETH)
13
- * - committee_epoch is hardcoded to 0 for now
14
- * - aggregated_signatures is concatenation of 65-byte ECDSA signatures (r,s,v)
15
- * - proof is the deposit TX hash (subject to change in the future)
10
+ * - Token addresses on Pod and ETH are different (deposit AAAA on Pod, claim BBBB on ETH)
11
+ * - For USDC-like tokens, use ETH-side decimals (e.g. parseUnits('1', 6) for USDC)
12
+ * - Pod system contract handles balance internally - do NOT set tx value
16
13
  */
17
14
  export declare class PodToSourceChainActionClient {
18
15
  private readonly config;
19
- private readonly iface;
16
+ private readonly podIface;
17
+ private readonly sourceChainIface;
20
18
  constructor(config: PodBridgeActionsClientConfig);
21
19
  /**
22
- * Create unsigned transaction for depositing ERC20 tokens from Pod to ETH
20
+ * Create unsigned transaction for depositing tokens from Pod to ETH
23
21
  *
24
22
  * After deposit:
25
- * - Get the TX receipt from Pod
26
- * - Call claim() on ETH with aggregated validator signatures
23
+ * - Call pod_getBridgeClaimProof(depositTxHash) on Pod RPC
24
+ * - Call claim() on ETH with the proof
27
25
  *
28
- * Note: Native tokens are not supported. Only ERC20.
29
- * Note: Token addresses differ between Pod and ETH chains.
26
+ * Note: Pod system contract handles balance deduction internally.
27
+ * Do NOT set transaction value - even for native token (0xEeee...EEeE) deposits.
28
+ * Use ETH-side decimals for amount (e.g. 1e6 for 1 USDC, not 1e18).
30
29
  *
31
- * @param args.token Token address on Pod to deposit
32
- * @param args.amount Amount to deposit (in wei)
30
+ * @param args.token Token address on Pod to deposit (use 0xEeee...EEeE for native)
31
+ * @param args.amount Amount to deposit (in ETH-side decimals)
33
32
  * @param args.destinationWalletAddress Recipient address on ETH
34
33
  * @param args.from Optional sender address
35
34
  * @returns Unsigned transaction template with encoded deposit call
@@ -41,12 +40,12 @@ export declare class PodToSourceChainActionClient {
41
40
  from?: string;
42
41
  }): UnsignedTransaction;
43
42
  /**
44
- * Create unsigned transaction for claiming ERC20 tokens on ETH (source chain)
43
+ * Create unsigned transaction for claiming tokens on ETH (source chain)
45
44
  *
46
- * This is called after depositing on Pod and getting the TX receipt.
47
- * The aggregated_signatures must be recovered to 65-byte format (r,s,v).
45
+ * This is called after depositing on Pod and obtaining the claim proof
46
+ * via pod_getBridgeClaimProof RPC (or the getBridgeClaimProof helper).
48
47
  *
49
- * @param args.claimData Claim proof data with aggregated signatures
48
+ * @param args.claimData Claim proof data with proof + auxTxSuffix
50
49
  * @param args.from Optional sender address
51
50
  * @returns Unsigned transaction template with encoded claim call
52
51
  */
@@ -6,41 +6,40 @@ const bridge_abi_1 = require("../../libs/abi/bridge.abi");
6
6
  /**
7
7
  * PodToSourceChainActionClient - Handles Pod -> ETH bridging
8
8
  *
9
- * New architecture:
10
- * - User deposits ERC20 tokens on Pod
11
- * - Wait for TX receipt from Pod
12
- * - User claims on ETH with aggregated validator signatures
13
- * - Only ERC20 tokens supported (no native tokens)
9
+ * - User deposits tokens on Pod
10
+ * - Call pod_getBridgeClaimProof(depositTxHash) to get proof
11
+ * - User claims on ETH with proof + auxTxSuffix
14
12
  *
15
13
  * Important notes:
16
- * - Token addresses on Pod and ETH are different (user deposits AAAA on Pod, claims BBBB on ETH)
17
- * - committee_epoch is hardcoded to 0 for now
18
- * - aggregated_signatures is concatenation of 65-byte ECDSA signatures (r,s,v)
19
- * - proof is the deposit TX hash (subject to change in the future)
14
+ * - Token addresses on Pod and ETH are different (deposit AAAA on Pod, claim BBBB on ETH)
15
+ * - For USDC-like tokens, use ETH-side decimals (e.g. parseUnits('1', 6) for USDC)
16
+ * - Pod system contract handles balance internally - do NOT set tx value
20
17
  */
21
18
  class PodToSourceChainActionClient {
22
19
  constructor(config) {
23
20
  this.config = config;
24
- this.iface = new ethers_1.Interface(bridge_abi_1.BRIDGE_ABI);
21
+ this.podIface = new ethers_1.Interface(bridge_abi_1.POD_BRIDGE_ABI);
22
+ this.sourceChainIface = new ethers_1.Interface(bridge_abi_1.SOURCE_CHAIN_BRIDGE_ABI);
25
23
  }
26
24
  /**
27
- * Create unsigned transaction for depositing ERC20 tokens from Pod to ETH
25
+ * Create unsigned transaction for depositing tokens from Pod to ETH
28
26
  *
29
27
  * After deposit:
30
- * - Get the TX receipt from Pod
31
- * - Call claim() on ETH with aggregated validator signatures
28
+ * - Call pod_getBridgeClaimProof(depositTxHash) on Pod RPC
29
+ * - Call claim() on ETH with the proof
32
30
  *
33
- * Note: Native tokens are not supported. Only ERC20.
34
- * Note: Token addresses differ between Pod and ETH chains.
31
+ * Note: Pod system contract handles balance deduction internally.
32
+ * Do NOT set transaction value - even for native token (0xEeee...EEeE) deposits.
33
+ * Use ETH-side decimals for amount (e.g. 1e6 for 1 USDC, not 1e18).
35
34
  *
36
- * @param args.token Token address on Pod to deposit
37
- * @param args.amount Amount to deposit (in wei)
35
+ * @param args.token Token address on Pod to deposit (use 0xEeee...EEeE for native)
36
+ * @param args.amount Amount to deposit (in ETH-side decimals)
38
37
  * @param args.destinationWalletAddress Recipient address on ETH
39
38
  * @param args.from Optional sender address
40
39
  * @returns Unsigned transaction template with encoded deposit call
41
40
  */
42
41
  deposit(args) {
43
- const data = this.iface.encodeFunctionData('deposit', [
42
+ const data = this.podIface.encodeFunctionData('deposit', [
44
43
  args.token,
45
44
  args.amount,
46
45
  args.destinationWalletAddress
@@ -53,24 +52,23 @@ class PodToSourceChainActionClient {
53
52
  };
54
53
  }
55
54
  /**
56
- * Create unsigned transaction for claiming ERC20 tokens on ETH (source chain)
55
+ * Create unsigned transaction for claiming tokens on ETH (source chain)
57
56
  *
58
- * This is called after depositing on Pod and getting the TX receipt.
59
- * The aggregated_signatures must be recovered to 65-byte format (r,s,v).
57
+ * This is called after depositing on Pod and obtaining the claim proof
58
+ * via pod_getBridgeClaimProof RPC (or the getBridgeClaimProof helper).
60
59
  *
61
- * @param args.claimData Claim proof data with aggregated signatures
60
+ * @param args.claimData Claim proof data with proof + auxTxSuffix
62
61
  * @param args.from Optional sender address
63
62
  * @returns Unsigned transaction template with encoded claim call
64
63
  */
65
64
  claim(args) {
66
- const { ethTokenAddress, amount, to, committeeEpoch, aggregatedSignatures, depositTxHash } = args.claimData;
67
- const data = this.iface.encodeFunctionData('claim', [
65
+ const { ethTokenAddress, amount, to, proof, auxTxSuffix } = args.claimData;
66
+ const data = this.sourceChainIface.encodeFunctionData('claim', [
68
67
  ethTokenAddress,
69
68
  amount,
70
69
  to,
71
- committeeEpoch,
72
- aggregatedSignatures,
73
- depositTxHash
70
+ proof,
71
+ auxTxSuffix
74
72
  ]);
75
73
  return {
76
74
  to: this.config.sourceChain.contractAddress,
@@ -2,11 +2,9 @@ import { UnsignedTransaction, PodBridgeActionsClientConfig } from "../../libs/ty
2
2
  /**
3
3
  * SourceChainToPodActionClient - Handles ETH -> Pod bridging
4
4
  *
5
- * New architecture:
6
5
  * - User deposits ERC20 tokens on ETH (source chain)
7
- * - Balance is automatically added on Pod (~15 min on Sepolia, instant on Anvil)
6
+ * - Balance is automatically added on Pod after finalization
8
7
  * - NO claim transaction needed on Pod side (auto-claim)
9
- * - Only ERC20 tokens supported (wrap ETH to WETH first)
10
8
  */
11
9
  export declare class SourceChainToPodActionClient {
12
10
  private readonly config;
@@ -16,15 +14,17 @@ export declare class SourceChainToPodActionClient {
16
14
  * Create unsigned transaction for depositing ERC20 tokens from ETH to Pod
17
15
  *
18
16
  * After deposit:
19
- * - Wait for block finalization (~15 min on Sepolia, instant on Anvil)
17
+ * - Wait for block finalization
20
18
  * - Balance will be automatically added on Pod (no claim needed)
21
19
  *
22
- * Note: Native ETH is not supported. Wrap to WETH first.
23
20
  * Note: Token addresses differ between ETH and Pod chains.
21
+ * Note: For USDC-like tokens, use the token's decimals (e.g. parseUnits('1', 6)),
22
+ * not parseEther which assumes 18 decimals.
24
23
  *
25
24
  * @param args.token Token address on source chain (ETH) to deposit
26
- * @param args.amount Amount to deposit (in wei)
25
+ * @param args.amount Amount to deposit (in token's smallest unit)
27
26
  * @param args.destinationWalletAddress Recipient address on Pod
27
+ * @param args.permit Optional permit bytes for gasless approval (default '0x')
28
28
  * @param args.from Optional sender address
29
29
  * @returns Unsigned transaction template with encoded deposit call
30
30
  */
@@ -32,6 +32,7 @@ export declare class SourceChainToPodActionClient {
32
32
  token: string;
33
33
  amount: string | bigint;
34
34
  destinationWalletAddress: string;
35
+ permit?: string;
35
36
  from?: string;
36
37
  }): UnsignedTransaction;
37
38
  }