@tapforce/pod-bridge-sdk 1.0.1 → 1.1.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
@@ -34,7 +34,8 @@ pnpm add @tapforce/pod-bridge-sdk
34
34
 
35
35
  ```typescript
36
36
  import {
37
- PodBridgeActionClient,
37
+ BridgedToPodActionClient,
38
+ PodToBridgedActionClient,
38
39
  PodBridgeTrackerClient,
39
40
  PodBridgeConfig
40
41
  } from '@tapforce/pod-bridge-sdk';
@@ -46,11 +47,11 @@ Create a configuration object with source and destination chain details:
46
47
 
47
48
  ```typescript
48
49
  const config: PodBridgeConfig = {
49
- source: {
50
+ bridged: {
50
51
  rpcUrl: 'https://sepolia.infura.io/v3/YOUR_KEY',
51
52
  contractAddress: '0x...' // Source chain bridge contract
52
53
  },
53
- destination: {
54
+ pod: {
54
55
  rpcUrl: 'https://pod-rpc.example.com',
55
56
  contractAddress: '0x...' // Destination chain bridge contract
56
57
  }
@@ -59,94 +60,109 @@ const config: PodBridgeConfig = {
59
60
 
60
61
  ## Usage
61
62
 
62
- ### 1. Action Client - Creating Transactions
63
+ ### 1. Action Clients - Creating Transactions
63
64
 
64
- The `PodBridgeActionClient` creates unsigned transactions that you can sign and broadcast.
65
+ The SDK provides two action clients for different bridge directions:
65
66
 
66
- #### Deposit ERC20 Tokens
67
+ - **`BridgedToPodActionClient`**: For Bridged → POD transfers (e.g., Sepolia → POD)
68
+ - **`PodToBridgedActionClient`**: For POD → Bridged transfers (e.g., POD → Sepolia)
69
+
70
+ #### Configuration for Action Clients
67
71
 
68
72
  ```typescript
69
- const actionClient = new PodBridgeActionClient();
73
+ const actionConfig = {
74
+ bridged: {
75
+ contractAddress: '0x...' // Bridged chain bridge contract (e.g., Sepolia)
76
+ },
77
+ pod: {
78
+ contractAddress: '0x...' // POD chain bridge contract
79
+ }
80
+ };
81
+
82
+ const bridgedToPodClient = new BridgedToPodActionClient(actionConfig);
83
+ const podToBridgedClient = new PodToBridgedActionClient(actionConfig);
84
+ ```
85
+
86
+ #### Deposit from Bridged Chain (e.g., Sepolia → POD)
70
87
 
71
- // Create unsigned transaction for ERC20 deposit
72
- const unsignedTx = actionClient.depositToken({
88
+ ```typescript
89
+ // Create unsigned transaction for ERC20 deposit on Bridged chain
90
+ const unsignedTx = bridgedToPodClient.depositToken({
73
91
  token: '0x...', // ERC20 token address
74
92
  amount: '1000000000000000000', // Amount in wei (1 token with 18 decimals)
75
- recipient: '0x...', // Recipient address on destination chain
76
- contractAddress: config.source.contractAddress,
93
+ destinationWalletAddress: '0x...', // Recipient address on POD
77
94
  from: '0x...' // Optional: sender address
78
95
  });
79
96
 
80
- // Sign and send transaction using your wallet/provider
81
- // const tx = await signer.sendTransaction(unsignedTx);
82
- ```
83
-
84
- #### Deposit Native Tokens (ETH)
85
-
86
- ```typescript
87
- // Create unsigned transaction for native token deposit
88
- const unsignedTx = actionClient.depositNative({
97
+ // Deposit native tokens
98
+ const unsignedNativeTx = bridgedToPodClient.depositNative({
89
99
  amount: '1000000000000000000', // Amount in wei (1 ETH)
90
- recipient: '0x...', // Recipient address on destination chain
91
- contractAddress: config.source.contractAddress,
100
+ destinationWalletAddress: '0x...', // Recipient address on POD
92
101
  from: '0x...' // Optional: sender address
93
102
  });
94
103
 
95
- // Sign and send transaction
104
+ // Sign and send transaction using your wallet/provider
96
105
  // const tx = await signer.sendTransaction(unsignedTx);
97
106
  ```
98
107
 
99
- #### Claim Tokens (with Certificate) - Sepolia from POD
108
+ #### Claim on POD from Bridged Chain Deposits
100
109
 
101
- For claiming on Sepolia from POD deposits, use certificate-based claims:
110
+ For claiming on POD from Bridged chain deposits, use block number-based claims:
102
111
 
103
112
  ```typescript
104
- // Obtain certified log from POD certificate system
105
- const certifiedLog = {
106
- log: {
107
- addr: '0x...',
108
- topics: ['0x...'],
109
- data: '0x...'
110
- },
111
- sigs: [
112
- { r: '0x...', s: '0x...', v: 27 }
113
- ]
114
- };
115
-
116
- // Create unsigned claim transaction for ERC20
117
- const unsignedTx = actionClient.claimWithCertificate({
118
- certifiedLog,
119
- contractAddress: config.destination.contractAddress,
113
+ // Create unsigned claim transaction for ERC20 on POD
114
+ const unsignedTx = bridgedToPodClient.claimWithBlockNumber({
115
+ id: '123', // Request ID from deposit event
116
+ token: '0x...', // Token address on source chain
117
+ blockNumber: 12345678, // Block number of deposit on source chain
120
118
  from: '0x...' // Optional: claimer address
121
119
  });
122
120
 
123
121
  // For native tokens
124
- const unsignedNativeTx = actionClient.claimNativeWithCertificate({
125
- certifiedLog,
126
- contractAddress: config.destination.contractAddress,
122
+ const unsignedNativeTx = bridgedToPodClient.claimNativeWithBlockNumber({
123
+ id: '123',
124
+ blockNumber: 12345678,
127
125
  from: '0x...'
128
126
  });
129
127
  ```
130
128
 
131
- #### Claim Tokens (with Block Number) - POD from Sepolia
129
+ #### Deposit from POD (POD Bridged Chain)
132
130
 
133
- For claiming on POD from Sepolia deposits, use block number-based claims:
131
+ ```typescript
132
+ // Create unsigned transaction for ERC20 deposit on POD
133
+ const unsignedTx = podToBridgedClient.depositToken({
134
+ token: '0x...', // ERC20 token address
135
+ amount: '1000000000000000000', // Amount in wei
136
+ destinationWalletAddress: '0x...', // Recipient address on Bridged chain
137
+ from: '0x...' // Optional: sender address
138
+ });
139
+
140
+ // Deposit native tokens
141
+ const unsignedNativeTx = podToBridgedClient.depositNative({
142
+ amount: '1000000000000000000',
143
+ destinationWalletAddress: '0x...',
144
+ from: '0x...'
145
+ });
146
+ ```
147
+
148
+ #### Claim on Bridged Chain from POD Deposits
149
+
150
+ For claiming on Bridged chain from POD deposits, use certificate-based claims. First, get the certified log from the POD deposit transaction:
134
151
 
135
152
  ```typescript
136
- // Create unsigned claim transaction for ERC20
137
- const unsignedTx = actionClient.claimWithBlockNumber({
138
- id: '123', // Request ID from deposit event
139
- token: '0x...', // Token address on source chain
140
- blockNumber: 12345678, // Block number of deposit on source chain
141
- contractAddress: config.destination.contractAddress,
153
+ // Get certified log from POD deposit transaction
154
+ const depositTxHash = '0x...'; // Transaction hash of deposit on POD
155
+ const certifiedLog = await trackerClient.getDepositCertifiedLog(depositTxHash);
156
+
157
+ // Create unsigned claim transaction for ERC20 on Bridged chain
158
+ const unsignedTx = podToBridgedClient.claimWithCertificate({
159
+ certifiedLog,
142
160
  from: '0x...' // Optional: claimer address
143
161
  });
144
162
 
145
163
  // For native tokens
146
- const unsignedNativeTx = actionClient.claimNativeWithBlockNumber({
147
- id: '123',
148
- blockNumber: 12345678,
149
- contractAddress: config.destination.contractAddress,
164
+ const unsignedNativeTx = podToBridgedClient.claimNativeWithCertificate({
165
+ certifiedLog,
150
166
  from: '0x...'
151
167
  });
152
168
  ```
@@ -232,44 +248,69 @@ processedStatuses.forEach((isProcessed, index) => {
232
248
 
233
249
  ## API Reference
234
250
 
235
- ### PodBridgeActionClient
251
+ ### BridgedToPodActionClient
252
+
253
+ Handles transactions for Bridged → POD direction.
254
+
255
+ #### Constructor
256
+
257
+ ```typescript
258
+ new BridgedToPodActionClient(config: PodBridgeActionsClientConfig)
259
+ ```
236
260
 
237
261
  #### Methods
238
262
 
239
- - **`depositToken(args)`**: Create unsigned transaction for ERC20 deposit
263
+ - **`depositToken(args)`**: Create unsigned transaction for ERC20 deposit on Bridged chain
240
264
  - `token`: Token address
241
265
  - `amount`: Amount in wei (string | bigint)
242
- - `recipient`: Recipient address on destination chain
243
- - `contractAddress`: Bridge contract address
266
+ - `destinationWalletAddress`: Recipient address on POD
244
267
  - `from?`: Optional sender address
245
268
 
246
- - **`depositNative(args)`**: Create unsigned transaction for native token deposit
269
+ - **`depositNative(args)`**: Create unsigned transaction for native token deposit on Bridged chain
247
270
  - `amount`: Amount in wei (string | bigint)
248
- - `recipient`: Recipient address on destination chain
249
- - `contractAddress`: Bridge contract address
271
+ - `destinationWalletAddress`: Recipient address on POD
250
272
  - `from?`: Optional sender address
251
273
 
252
- - **`claimWithCertificate(args)`**: Create unsigned transaction for claiming with certificate
253
- - `certifiedLog`: Certified log from POD certificate system
254
- - `contractAddress`: Bridge contract address
274
+ - **`claimWithBlockNumber(args)`**: Create unsigned transaction for claiming on POD with block number
275
+ - `id`: Request ID
276
+ - `token`: Token address
277
+ - `blockNumber`: Block number of deposit on Bridged chain
255
278
  - `from?`: Optional claimer address
256
279
 
257
- - **`claimNativeWithCertificate(args)`**: Create unsigned transaction for claiming native tokens with certificate
258
- - `certifiedLog`: Certified log from POD certificate system
259
- - `contractAddress`: Bridge contract address
280
+ - **`claimNativeWithBlockNumber(args)`**: Create unsigned transaction for claiming native tokens on POD with block number
281
+ - `id`: Request ID
282
+ - `blockNumber`: Block number of deposit on Bridged chain
260
283
  - `from?`: Optional claimer address
261
284
 
262
- - **`claimWithBlockNumber(args)`**: Create unsigned transaction for claiming with block number
263
- - `id`: Request ID
285
+ ### PodToBridgedActionClient
286
+
287
+ Handles transactions for POD → Bridged direction.
288
+
289
+ #### Constructor
290
+
291
+ ```typescript
292
+ new PodToBridgedActionClient(config: PodBridgeActionsClientConfig)
293
+ ```
294
+
295
+ #### Methods
296
+
297
+ - **`depositToken(args)`**: Create unsigned transaction for ERC20 deposit on POD
264
298
  - `token`: Token address
265
- - `blockNumber`: Block number of deposit
266
- - `contractAddress`: Bridge contract address
299
+ - `amount`: Amount in wei (string | bigint)
300
+ - `destinationWalletAddress`: Recipient address on Bridged chain
301
+ - `from?`: Optional sender address
302
+
303
+ - **`depositNative(args)`**: Create unsigned transaction for native token deposit on POD
304
+ - `amount`: Amount in wei (string | bigint)
305
+ - `destinationWalletAddress`: Recipient address on Bridged chain
306
+ - `from?`: Optional sender address
307
+
308
+ - **`claimWithCertificate(args)`**: Create unsigned transaction for claiming on Bridged chain with certificate
309
+ - `certifiedLog`: Certified log from POD certificate system
267
310
  - `from?`: Optional claimer address
268
311
 
269
- - **`claimNativeWithBlockNumber(args)`**: Create unsigned transaction for claiming native tokens with block number
270
- - `id`: Request ID
271
- - `blockNumber`: Block number of deposit
272
- - `contractAddress`: Bridge contract address
312
+ - **`claimNativeWithCertificate(args)`**: Create unsigned transaction for claiming native tokens on Bridged chain with certificate
313
+ - `certifiedLog`: Certified log from POD certificate system
273
314
  - `from?`: Optional claimer address
274
315
 
275
316
  ### PodBridgeTrackerClient
@@ -291,6 +332,10 @@ processedStatuses.forEach((isProcessed, index) => {
291
332
  - **`areRequestsProcessed(deposits)`**: Batch check if requests are processed
292
333
  - Returns: `Promise<boolean[]>`
293
334
 
335
+ - **`getDepositCertifiedLog(txHash)`**: Get certified log for claiming on Sepolia from POD deposit
336
+ - `txHash`: Transaction hash of deposit on POD
337
+ - Returns: `Promise<CertifiedLog>` with attestations and merkle proof
338
+
294
339
  ## Types
295
340
 
296
341
  ### BridgeRequest
@@ -334,11 +379,18 @@ interface CertifiedLog {
334
379
  topics: string[];
335
380
  data: string;
336
381
  };
337
- sigs: Array<{
338
- r: string;
339
- s: string;
340
- v: number;
341
- }>;
382
+ logIndex: bigint | string;
383
+ certificate: {
384
+ leaf: string;
385
+ certifiedReceipt: {
386
+ receiptRoot: string;
387
+ aggregateSignature: string;
388
+ sortedAttestationTimestamps: bigint[] | string[];
389
+ };
390
+ proof: {
391
+ path: string[];
392
+ };
393
+ };
342
394
  }
343
395
  ```
344
396
 
@@ -358,65 +410,125 @@ The SDK supports two bridge implementations:
358
410
 
359
411
  ## Examples
360
412
 
361
- ### Complete Deposit and Claim Flow
413
+ ### Complete Deposit and Claim Flow (Sepolia → POD)
362
414
 
363
415
  ```typescript
364
416
  import { ethers } from 'ethers';
365
- import { PodBridgeActionClient, PodBridgeTrackerClient } from '@tapforce/pod-bridge-sdk';
417
+ import { BridgedToPodActionClient, PodBridgeTrackerClient } from '@tapforce/pod-bridge-sdk';
366
418
 
367
419
  // Setup
368
- const config = {
369
- source: {
420
+ const trackerConfig = {
421
+ bridged: {
370
422
  rpcUrl: 'https://sepolia.infura.io/v3/YOUR_KEY',
371
- contractAddress: '0xSourceBridgeContract'
423
+ contractAddress: '0xSepoliaBridgeContract'
372
424
  },
373
- destination: {
374
- rpcUrl: 'https://pod-rpc.example.com',
375
- contractAddress: '0xDestBridgeContract'
425
+ pod: {
426
+ rpcUrl: 'https://rpc.v1.dev.pod.network',
427
+ contractAddress: '0xPodBridgeContract'
376
428
  }
377
429
  };
378
430
 
379
- const actionClient = new PodBridgeActionClient();
380
- const trackerClient = new PodBridgeTrackerClient(config);
381
- const provider = new ethers.JsonRpcProvider(config.source.rpcUrl);
382
- const signer = new ethers.Wallet('PRIVATE_KEY', provider);
431
+ const actionConfig = {
432
+ bridged: { contractAddress: '0xSepoliaBridgeContract' },
433
+ pod: { contractAddress: '0xPodBridgeContract' }
434
+ };
383
435
 
384
- // Step 1: Deposit tokens
436
+ const actionClient = new BridgedToPodActionClient(actionConfig);
437
+ const trackerClient = new PodBridgeTrackerClient(trackerConfig);
438
+ const sepoliaProvider = new ethers.JsonRpcProvider(trackerConfig.bridged.rpcUrl);
439
+ const sepoliaSigner = new ethers.Wallet('PRIVATE_KEY', sepoliaProvider);
440
+
441
+ // Step 1: Deposit tokens on Sepolia
385
442
  const depositTx = actionClient.depositToken({
386
443
  token: '0xTokenAddress',
387
444
  amount: ethers.parseEther('10').toString(),
388
- recipient: await signer.getAddress(),
389
- contractAddress: config.source.contractAddress
445
+ destinationWalletAddress: await sepoliaSigner.getAddress()
390
446
  });
391
447
 
392
- const tx = await signer.sendTransaction(depositTx);
448
+ const tx = await sepoliaSigner.sendTransaction(depositTx);
393
449
  await tx.wait();
394
450
  console.log(`Deposit tx: ${tx.hash}`);
395
451
 
396
452
  // Step 2: Track deposit
397
- const deposits = await trackerClient.getDepositsSentBy(await signer.getAddress());
453
+ const deposits = await trackerClient.getDepositsSentBy(await sepoliaSigner.getAddress());
398
454
  const latestDeposit = deposits[0];
399
455
 
400
456
  console.log(`Request ID: ${latestDeposit.requestId}`);
401
457
  console.log(`Amount: ${ethers.formatEther(latestDeposit.amount)}`);
402
458
 
403
- // Step 3: Wait for finality and claim
459
+ // Step 3: Wait for finality and claim on POD
404
460
  const canClaim = await trackerClient.canBeClaimed(latestDeposit);
405
461
  if (canClaim) {
406
462
  const claimTx = actionClient.claimWithBlockNumber({
407
463
  id: latestDeposit.requestId,
408
464
  token: latestDeposit.token,
409
- blockNumber: latestDeposit.blockNumber,
410
- contractAddress: config.destination.contractAddress
465
+ blockNumber: latestDeposit.blockNumber
411
466
  });
412
467
 
413
- // Submit claim on destination chain
414
- // const destSigner = new ethers.Wallet('PRIVATE_KEY', destProvider);
415
- // const claim = await destSigner.sendTransaction(claimTx);
416
- // await claim.wait();
468
+ // Submit claim on POD
469
+ const podProvider = new ethers.JsonRpcProvider(trackerConfig.pod.rpcUrl);
470
+ const podSigner = new ethers.Wallet('PRIVATE_KEY', podProvider);
471
+ const claim = await podSigner.sendTransaction(claimTx);
472
+ await claim.wait();
473
+ console.log(`Claimed on POD: ${claim.hash}`);
417
474
  }
418
475
  ```
419
476
 
477
+ ### Complete Deposit and Claim Flow (POD → Sepolia)
478
+
479
+ ```typescript
480
+ import { ethers } from 'ethers';
481
+ import { PodToBridgedActionClient, PodBridgeTrackerClient } from '@tapforce/pod-bridge-sdk';
482
+
483
+ // Setup
484
+ const trackerConfig = {
485
+ bridged: {
486
+ rpcUrl: 'https://sepolia.infura.io/v3/YOUR_KEY',
487
+ contractAddress: '0xSepoliaBridgeContract'
488
+ },
489
+ pod: {
490
+ rpcUrl: 'https://rpc.v1.dev.pod.network',
491
+ contractAddress: '0xPodBridgeContract'
492
+ }
493
+ };
494
+
495
+ const actionConfig = {
496
+ bridged: { contractAddress: '0xSepoliaBridgeContract' },
497
+ pod: { contractAddress: '0xPodBridgeContract' }
498
+ };
499
+
500
+ const actionClient = new PodToBridgedActionClient(actionConfig);
501
+ const trackerClient = new PodBridgeTrackerClient(trackerConfig);
502
+ const podProvider = new ethers.JsonRpcProvider(trackerConfig.pod.rpcUrl);
503
+ const podSigner = new ethers.Wallet('PRIVATE_KEY', podProvider);
504
+
505
+ // Step 1: Deposit tokens on POD
506
+ const depositTx = actionClient.depositToken({
507
+ token: '0xTokenAddress',
508
+ amount: ethers.parseEther('10').toString(),
509
+ destinationWalletAddress: await podSigner.getAddress()
510
+ });
511
+
512
+ const tx = await podSigner.sendTransaction(depositTx);
513
+ const receipt = await tx.wait();
514
+ console.log(`Deposit tx on POD: ${tx.hash}`);
515
+
516
+ // Step 2: Get certified log from POD transaction
517
+ const certifiedLog = await trackerClient.getDepositCertifiedLog(tx.hash);
518
+ console.log('Got certified log with attestations');
519
+
520
+ // Step 3: Claim on Sepolia using certified log
521
+ const claimTx = actionClient.claimWithCertificate({
522
+ certifiedLog
523
+ });
524
+
525
+ const sepoliaProvider = new ethers.JsonRpcProvider(trackerConfig.bridged.rpcUrl);
526
+ const sepoliaSigner = new ethers.Wallet('PRIVATE_KEY', sepoliaProvider);
527
+ const claim = await sepoliaSigner.sendTransaction(claimTx);
528
+ await claim.wait();
529
+ console.log(`Claimed on Sepolia: ${claim.hash}`);
530
+ ```
531
+
420
532
  ## Development
421
533
 
422
534
  ### Build
@@ -1,12 +1,13 @@
1
- import { UnsignedTransaction, CertifiedLog } from "../../libs/types/pod-bridge.types";
2
- export declare class PodBridgeActionClient {
1
+ import { UnsignedTransaction, PodBridgeActionsClientConfig } from "../../libs/types/pod-bridge.types";
2
+ export declare class BridgedToPodActionClient {
3
+ private readonly config;
3
4
  private readonly iface;
4
- constructor();
5
+ constructor(config: PodBridgeActionsClientConfig);
5
6
  /**
6
7
  * Create unsigned transaction for depositing ERC20 tokens
7
8
  * @param args.token Token address to deposit
8
9
  * @param args.amount Amount to deposit (in wei)
9
- * @param args.recipient Recipient address on destination chain
10
+ * @param args.destinationWalletAddress Recipient address on destination chain
10
11
  * @param args.contractAddress Bridge contract address (source chain)
11
12
  * @param args.from Optional sender address
12
13
  * @returns Unsigned transaction template with encoded deposit call
@@ -14,48 +15,20 @@ export declare class PodBridgeActionClient {
14
15
  depositToken(args: {
15
16
  token: string;
16
17
  amount: string | bigint;
17
- recipient: string;
18
- contractAddress: string;
18
+ destinationWalletAddress: string;
19
19
  from?: string;
20
20
  }): UnsignedTransaction;
21
21
  /**
22
22
  * Create unsigned transaction for depositing native tokens (ETH)
23
23
  * @param args.amount Amount to deposit (in wei) - also set as transaction value
24
- * @param args.recipient Recipient address on destination chain
24
+ * @param args.destinationWalletAddress Recipient address on destination chain
25
25
  * @param args.contractAddress Bridge contract address (source chain)
26
26
  * @param args.from Optional sender address
27
27
  * @returns Unsigned transaction template with encoded depositNative call
28
28
  */
29
29
  depositNative(args: {
30
30
  amount: string | bigint;
31
- recipient: string;
32
- contractAddress: string;
33
- from?: string;
34
- }): UnsignedTransaction;
35
- /**
36
- * Create unsigned transaction for claiming tokens (BridgeDepositWithdraw - with certificates)
37
- * Used for claiming on Sepolia from POD deposits
38
- * @param args.certifiedLog Certified log from POD certificate system
39
- * @param args.contractAddress Bridge contract address (destination chain)
40
- * @param args.from Optional sender address
41
- * @returns Unsigned transaction template with encoded claim call
42
- */
43
- claimWithCertificate(args: {
44
- certifiedLog: CertifiedLog;
45
- contractAddress: string;
46
- from?: string;
47
- }): UnsignedTransaction;
48
- /**
49
- * Create unsigned transaction for claiming native tokens (BridgeDepositWithdraw - with certificates)
50
- * Used for claiming native tokens on Sepolia from POD deposits
51
- * @param args.certifiedLog Certified log from POD certificate system
52
- * @param args.contractAddress Bridge contract address (destination chain)
53
- * @param args.from Optional sender address
54
- * @returns Unsigned transaction template with encoded claimNative call
55
- */
56
- claimNativeWithCertificate(args: {
57
- certifiedLog: CertifiedLog;
58
- contractAddress: string;
31
+ destinationWalletAddress: string;
59
32
  from?: string;
60
33
  }): UnsignedTransaction;
61
34
  /**
@@ -1,17 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PodBridgeActionClient = void 0;
3
+ exports.BridgedToPodActionClient = void 0;
4
4
  const ethers_1 = require("ethers");
5
5
  const bridge_abi_1 = require("../../libs/abi/bridge.abi");
6
- class PodBridgeActionClient {
7
- constructor() {
6
+ class BridgedToPodActionClient {
7
+ constructor(config) {
8
+ this.config = config;
8
9
  this.iface = new ethers_1.Interface(bridge_abi_1.POD_BRIDGE_ABI);
9
10
  }
10
11
  /**
11
12
  * Create unsigned transaction for depositing ERC20 tokens
12
13
  * @param args.token Token address to deposit
13
14
  * @param args.amount Amount to deposit (in wei)
14
- * @param args.recipient Recipient address on destination chain
15
+ * @param args.destinationWalletAddress Recipient address on destination chain
15
16
  * @param args.contractAddress Bridge contract address (source chain)
16
17
  * @param args.from Optional sender address
17
18
  * @returns Unsigned transaction template with encoded deposit call
@@ -20,10 +21,10 @@ class PodBridgeActionClient {
20
21
  const data = this.iface.encodeFunctionData('deposit', [
21
22
  args.token,
22
23
  args.amount,
23
- args.recipient
24
+ args.destinationWalletAddress
24
25
  ]);
25
26
  return {
26
- to: args.contractAddress,
27
+ to: this.config.bridged.contractAddress,
27
28
  data,
28
29
  value: '0',
29
30
  from: args === null || args === void 0 ? void 0 : args.from
@@ -32,54 +33,20 @@ class PodBridgeActionClient {
32
33
  /**
33
34
  * Create unsigned transaction for depositing native tokens (ETH)
34
35
  * @param args.amount Amount to deposit (in wei) - also set as transaction value
35
- * @param args.recipient Recipient address on destination chain
36
+ * @param args.destinationWalletAddress Recipient address on destination chain
36
37
  * @param args.contractAddress Bridge contract address (source chain)
37
38
  * @param args.from Optional sender address
38
39
  * @returns Unsigned transaction template with encoded depositNative call
39
40
  */
40
41
  depositNative(args) {
41
- const data = this.iface.encodeFunctionData('depositNative', [args.recipient]);
42
+ const data = this.iface.encodeFunctionData('depositNative', [args.destinationWalletAddress]);
42
43
  return {
43
- to: args.contractAddress,
44
+ to: this.config.bridged.contractAddress,
44
45
  data,
45
46
  value: args.amount.toString(),
46
47
  from: args === null || args === void 0 ? void 0 : args.from
47
48
  };
48
49
  }
49
- /**
50
- * Create unsigned transaction for claiming tokens (BridgeDepositWithdraw - with certificates)
51
- * Used for claiming on Sepolia from POD deposits
52
- * @param args.certifiedLog Certified log from POD certificate system
53
- * @param args.contractAddress Bridge contract address (destination chain)
54
- * @param args.from Optional sender address
55
- * @returns Unsigned transaction template with encoded claim call
56
- */
57
- claimWithCertificate(args) {
58
- const data = this.iface.encodeFunctionData('claim', [args.certifiedLog]);
59
- return {
60
- to: args.contractAddress,
61
- data,
62
- value: '0',
63
- from: args === null || args === void 0 ? void 0 : args.from
64
- };
65
- }
66
- /**
67
- * Create unsigned transaction for claiming native tokens (BridgeDepositWithdraw - with certificates)
68
- * Used for claiming native tokens on Sepolia from POD deposits
69
- * @param args.certifiedLog Certified log from POD certificate system
70
- * @param args.contractAddress Bridge contract address (destination chain)
71
- * @param args.from Optional sender address
72
- * @returns Unsigned transaction template with encoded claimNative call
73
- */
74
- claimNativeWithCertificate(args) {
75
- const data = this.iface.encodeFunctionData('claimNative', [args.certifiedLog]);
76
- return {
77
- to: args.contractAddress,
78
- data,
79
- value: '0',
80
- from: args === null || args === void 0 ? void 0 : args.from
81
- };
82
- }
83
50
  /**
84
51
  * Create unsigned transaction for claiming tokens (BridgeMintBurn - using precompiles)
85
52
  * Used for claiming on POD from Sepolia deposits
@@ -97,7 +64,7 @@ class PodBridgeActionClient {
97
64
  args.blockNumber
98
65
  ]);
99
66
  return {
100
- to: args.contractAddress,
67
+ to: this.config.pod.contractAddress,
101
68
  data,
102
69
  value: '0',
103
70
  from: args === null || args === void 0 ? void 0 : args.from
@@ -115,11 +82,11 @@ class PodBridgeActionClient {
115
82
  claimNativeWithBlockNumber(args) {
116
83
  const data = this.iface.encodeFunctionData('claimNative(uint256,uint256)', [args.id, args.blockNumber]);
117
84
  return {
118
- to: args.contractAddress,
85
+ to: this.config.pod.contractAddress,
119
86
  data,
120
87
  value: '0',
121
88
  from: args === null || args === void 0 ? void 0 : args.from
122
89
  };
123
90
  }
124
91
  }
125
- exports.PodBridgeActionClient = PodBridgeActionClient;
92
+ exports.BridgedToPodActionClient = BridgedToPodActionClient;
@@ -0,0 +1,54 @@
1
+ import { UnsignedTransaction, CertifiedLog, PodBridgeActionsClientConfig } from "../../libs/types/pod-bridge.types";
2
+ export declare class PodToBridgedActionClient {
3
+ private readonly config;
4
+ private readonly iface;
5
+ constructor(config: PodBridgeActionsClientConfig);
6
+ /**
7
+ * Create unsigned transaction for depositing ERC20 tokens from POD to Bridged chain
8
+ * @param args.token Token address to deposit
9
+ * @param args.amount Amount to deposit (in wei)
10
+ * @param args.destinationWalletAddress Recipient address on destination chain
11
+ * @param args.from Optional sender address
12
+ * @returns Unsigned transaction template with encoded deposit call
13
+ */
14
+ depositToken(args: {
15
+ token: string;
16
+ amount: string | bigint;
17
+ destinationWalletAddress: string;
18
+ from?: string;
19
+ }): UnsignedTransaction;
20
+ /**
21
+ * Create unsigned transaction for depositing native tokens from POD to Bridged chain
22
+ * @param args.amount Amount to deposit (in wei) - also set as transaction value
23
+ * @param args.destinationWalletAddress Recipient address on destination chain
24
+ * @param args.from Optional sender address
25
+ * @returns Unsigned transaction template with encoded depositNative call
26
+ */
27
+ depositNative(args: {
28
+ amount: string | bigint;
29
+ destinationWalletAddress: string;
30
+ from?: string;
31
+ }): UnsignedTransaction;
32
+ /**
33
+ * Create unsigned transaction for claiming tokens on Bridged chain (BridgeDepositWithdraw - with certificates)
34
+ * Used for claiming on Bridged chain from POD deposits
35
+ * @param args.certifiedLog Certified log from POD certificate system
36
+ * @param args.from Optional sender address
37
+ * @returns Unsigned transaction template with encoded claim call
38
+ */
39
+ claimWithCertificate(args: {
40
+ certifiedLog: CertifiedLog;
41
+ from?: string;
42
+ }): UnsignedTransaction;
43
+ /**
44
+ * Create unsigned transaction for claiming native tokens on Bridged chain (BridgeDepositWithdraw - with certificates)
45
+ * Used for claiming native tokens on Bridged chain from POD deposits
46
+ * @param args.certifiedLog Certified log from POD certificate system
47
+ * @param args.from Optional sender address
48
+ * @returns Unsigned transaction template with encoded claimNative call
49
+ */
50
+ claimNativeWithCertificate(args: {
51
+ certifiedLog: CertifiedLog;
52
+ from?: string;
53
+ }): UnsignedTransaction;
54
+ }
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PodToBridgedActionClient = void 0;
4
+ const ethers_1 = require("ethers");
5
+ const bridge_abi_1 = require("../../libs/abi/bridge.abi");
6
+ class PodToBridgedActionClient {
7
+ constructor(config) {
8
+ this.config = config;
9
+ this.iface = new ethers_1.Interface(bridge_abi_1.POD_BRIDGE_ABI);
10
+ }
11
+ /**
12
+ * Create unsigned transaction for depositing ERC20 tokens from POD to Bridged chain
13
+ * @param args.token Token address to deposit
14
+ * @param args.amount Amount to deposit (in wei)
15
+ * @param args.destinationWalletAddress Recipient address on destination chain
16
+ * @param args.from Optional sender address
17
+ * @returns Unsigned transaction template with encoded deposit call
18
+ */
19
+ depositToken(args) {
20
+ const data = this.iface.encodeFunctionData('deposit', [
21
+ args.token,
22
+ args.amount,
23
+ args.destinationWalletAddress
24
+ ]);
25
+ return {
26
+ to: this.config.pod.contractAddress,
27
+ data,
28
+ value: '0',
29
+ from: args === null || args === void 0 ? void 0 : args.from
30
+ };
31
+ }
32
+ /**
33
+ * Create unsigned transaction for depositing native tokens from POD to Bridged chain
34
+ * @param args.amount Amount to deposit (in wei) - also set as transaction value
35
+ * @param args.destinationWalletAddress Recipient address on destination chain
36
+ * @param args.from Optional sender address
37
+ * @returns Unsigned transaction template with encoded depositNative call
38
+ */
39
+ depositNative(args) {
40
+ const data = this.iface.encodeFunctionData('depositNative', [args.destinationWalletAddress]);
41
+ return {
42
+ to: this.config.pod.contractAddress,
43
+ data,
44
+ value: args.amount.toString(),
45
+ from: args === null || args === void 0 ? void 0 : args.from
46
+ };
47
+ }
48
+ /**
49
+ * Create unsigned transaction for claiming tokens on Bridged chain (BridgeDepositWithdraw - with certificates)
50
+ * Used for claiming on Bridged chain from POD deposits
51
+ * @param args.certifiedLog Certified log from POD certificate system
52
+ * @param args.from Optional sender address
53
+ * @returns Unsigned transaction template with encoded claim call
54
+ */
55
+ claimWithCertificate(args) {
56
+ const data = this.iface.encodeFunctionData('claim', [args.certifiedLog]);
57
+ return {
58
+ to: this.config.bridged.contractAddress,
59
+ data,
60
+ value: '0',
61
+ from: args === null || args === void 0 ? void 0 : args.from
62
+ };
63
+ }
64
+ /**
65
+ * Create unsigned transaction for claiming native tokens on Bridged chain (BridgeDepositWithdraw - with certificates)
66
+ * Used for claiming native tokens on Bridged chain from POD deposits
67
+ * @param args.certifiedLog Certified log from POD certificate system
68
+ * @param args.from Optional sender address
69
+ * @returns Unsigned transaction template with encoded claimNative call
70
+ */
71
+ claimNativeWithCertificate(args) {
72
+ const data = this.iface.encodeFunctionData('claimNative', [args.certifiedLog]);
73
+ return {
74
+ to: this.config.bridged.contractAddress,
75
+ data,
76
+ value: '0',
77
+ from: args === null || args === void 0 ? void 0 : args.from
78
+ };
79
+ }
80
+ }
81
+ exports.PodToBridgedActionClient = PodToBridgedActionClient;
@@ -1,10 +1,10 @@
1
- import { PodBridgeConfig, BridgeRequest, BridgeRequestWithType } from "../../libs/types/pod-bridge.types";
1
+ import { PodBridgeConfig, BridgeRequest, BridgeRequestWithType, CertifiedLog } from "../../libs/types/pod-bridge.types";
2
2
  export declare class PodBridgeTrackerClient {
3
3
  private readonly config;
4
- private readonly sourceProvider;
5
- private readonly destProvider;
6
- private readonly sourceBridge;
7
- private readonly destBridge;
4
+ private readonly bridgedProvider;
5
+ private readonly podProvider;
6
+ private readonly bridgedBridge;
7
+ private readonly podBridge;
8
8
  private readonly iface;
9
9
  constructor(config: PodBridgeConfig);
10
10
  /**
@@ -54,4 +54,36 @@ export declare class PodBridgeTrackerClient {
54
54
  * @returns Request hash
55
55
  */
56
56
  private computeRequestHash;
57
+ /**
58
+ * Get certified log for a deposit transaction from POD
59
+ * This is required to claim tokens on Sepolia from POD deposits
60
+ * @param txHash Transaction hash of the deposit on POD
61
+ * @returns Certified log with attestations and merkle proof
62
+ */
63
+ getDepositCertifiedLog(txHash: string): Promise<CertifiedLog>;
64
+ /**
65
+ * Compute receipt root hash
66
+ * @private
67
+ */
68
+ private computeReceiptRoot;
69
+ /**
70
+ * Aggregate signatures from attestations
71
+ * @private
72
+ */
73
+ private aggregateSignatures;
74
+ /**
75
+ * Hash a log entry
76
+ * @private
77
+ */
78
+ private hashLog;
79
+ /**
80
+ * Hash a leaf for merkle tree
81
+ * @private
82
+ */
83
+ private hashLeaf;
84
+ /**
85
+ * Generate merkle proof for a log at given index
86
+ * @private
87
+ */
88
+ private generateMerkleProof;
57
89
  }
@@ -8,11 +8,11 @@ class PodBridgeTrackerClient {
8
8
  constructor(config) {
9
9
  this.config = config;
10
10
  // Initialize providers
11
- this.sourceProvider = new ethers_1.ethers.JsonRpcProvider(config.source.rpcUrl);
12
- this.destProvider = new ethers_1.ethers.JsonRpcProvider(config.destination.rpcUrl);
11
+ this.bridgedProvider = new ethers_1.ethers.JsonRpcProvider(config.bridged.rpcUrl);
12
+ this.podProvider = new ethers_1.ethers.JsonRpcProvider(config.pod.rpcUrl);
13
13
  // Initialize contract instances
14
- this.sourceBridge = new ethers_1.Contract(config.source.contractAddress, bridge_abi_1.POD_BRIDGE_ABI, this.sourceProvider);
15
- this.destBridge = new ethers_1.Contract(config.destination.contractAddress, bridge_abi_1.POD_BRIDGE_ABI, this.destProvider);
14
+ this.bridgedBridge = new ethers_1.Contract(config.bridged.contractAddress, bridge_abi_1.POD_BRIDGE_ABI, this.bridgedProvider);
15
+ this.podBridge = new ethers_1.Contract(config.pod.contractAddress, bridge_abi_1.POD_BRIDGE_ABI, this.podProvider);
16
16
  // Interface for parsing logs
17
17
  this.iface = new ethers_1.Interface(bridge_abi_1.POD_BRIDGE_ABI);
18
18
  }
@@ -23,24 +23,23 @@ class PodBridgeTrackerClient {
23
23
  * @returns Array of bridge requests sent by this address
24
24
  */
25
25
  async getDepositsSentBy(address, fromBlock = 0) {
26
- console.log(`Fetching deposits sent by ${address}...`);
27
26
  const deposits = [];
28
- const currentBlock = await this.sourceProvider.getBlockNumber();
27
+ const currentBlock = await this.bridgedProvider.getBlockNumber();
29
28
  const BLOCK_BATCH_SIZE = 10000;
30
29
  for (let start = fromBlock; start <= currentBlock; start += BLOCK_BATCH_SIZE) {
31
30
  const end = Math.min(start + BLOCK_BATCH_SIZE - 1, currentBlock);
32
31
  // With improved events, we can filter by 'from' directly!
33
- const depositFilter = this.sourceBridge.filters.Deposit(null, // id
32
+ const depositFilter = this.bridgedBridge.filters.Deposit(null, // id
34
33
  address, // from (indexed) - Filter by sender!
35
34
  null // to
36
35
  );
37
- const depositNativeFilter = this.sourceBridge.filters.DepositNative(null, // id
36
+ const depositNativeFilter = this.bridgedBridge.filters.DepositNative(null, // id
38
37
  address, // from (indexed) - Filter by sender!
39
38
  null // to
40
39
  );
41
40
  const [depositLogs, depositNativeLogs] = await Promise.all([
42
- this.sourceBridge.queryFilter(depositFilter, start, end),
43
- this.sourceBridge.queryFilter(depositNativeFilter, start, end)
41
+ this.bridgedBridge.queryFilter(depositFilter, start, end),
42
+ this.bridgedBridge.queryFilter(depositNativeFilter, start, end)
44
43
  ]);
45
44
  // Process Deposit events
46
45
  for (const log of depositLogs) {
@@ -94,24 +93,23 @@ class PodBridgeTrackerClient {
94
93
  * @returns Array of bridge requests sent to this address
95
94
  */
96
95
  async getDepositsReceivedBy(address, fromBlock = 0) {
97
- console.log(`Fetching deposits received by ${address}...`);
98
96
  const deposits = [];
99
- const currentBlock = await this.sourceProvider.getBlockNumber();
97
+ const currentBlock = await this.bridgedProvider.getBlockNumber();
100
98
  const BLOCK_BATCH_SIZE = 10000;
101
99
  for (let start = fromBlock; start <= currentBlock; start += BLOCK_BATCH_SIZE) {
102
100
  const end = Math.min(start + BLOCK_BATCH_SIZE - 1, currentBlock);
103
101
  // With improved events, we can filter by 'to' directly!
104
- const depositFilter = this.sourceBridge.filters.Deposit(null, // id
102
+ const depositFilter = this.bridgedBridge.filters.Deposit(null, // id
105
103
  null, // from
106
104
  address // to (indexed) - Filter by recipient!
107
105
  );
108
- const depositNativeFilter = this.sourceBridge.filters.DepositNative(null, // id
106
+ const depositNativeFilter = this.bridgedBridge.filters.DepositNative(null, // id
109
107
  null, // from
110
108
  address // to (indexed) - Filter by recipient!
111
109
  );
112
110
  const [depositLogs, depositNativeLogs] = await Promise.all([
113
- this.sourceBridge.queryFilter(depositFilter, start, end),
114
- this.sourceBridge.queryFilter(depositNativeFilter, start, end)
111
+ this.bridgedBridge.queryFilter(depositFilter, start, end),
112
+ this.bridgedBridge.queryFilter(depositNativeFilter, start, end)
115
113
  ]);
116
114
  // Process Deposit events
117
115
  for (const log of depositLogs) {
@@ -165,7 +163,6 @@ class PodBridgeTrackerClient {
165
163
  * @returns Array of bridge requests with type indicator
166
164
  */
167
165
  async getAllDepositsFor(address, fromBlock = 0) {
168
- console.log(`Fetching all deposits for ${address}...`);
169
166
  // Fetch both sent and received in parallel
170
167
  const [sent, received] = await Promise.all([
171
168
  this.getDepositsSentBy(address, fromBlock),
@@ -205,7 +202,7 @@ class PodBridgeTrackerClient {
205
202
  * @returns True if the deposit can be claimed
206
203
  */
207
204
  async canBeClaimed(deposit) {
208
- const currentBlock = await this.sourceProvider.getBlockNumber();
205
+ const currentBlock = await this.bridgedProvider.getBlockNumber();
209
206
  const finalizedBlock = currentBlock - 15; // ~15 minutes on Sepolia
210
207
  return deposit.blockNumber <= finalizedBlock && !deposit.isClaimed;
211
208
  }
@@ -214,16 +211,16 @@ class PodBridgeTrackerClient {
214
211
  * @param deposits Array of deposits to check
215
212
  */
216
213
  async updateClaimStatus(deposits) {
217
- if (deposits.length === 0)
214
+ if (deposits.length === 0) {
218
215
  return;
219
- console.log(`Checking claim status for ${deposits.length} deposits...`);
216
+ }
220
217
  try {
221
218
  // Get claim events from destination chain
222
- const claimFilter = this.destBridge.filters.Claim();
223
- const claimNativeFilter = this.destBridge.filters.ClaimNative();
219
+ const claimFilter = this.podBridge.filters.Claim();
220
+ const claimNativeFilter = this.podBridge.filters.ClaimNative();
224
221
  const [claimLogs, claimNativeLogs] = await Promise.all([
225
- this.destBridge.queryFilter(claimFilter),
226
- this.destBridge.queryFilter(claimNativeFilter)
222
+ this.podBridge.queryFilter(claimFilter),
223
+ this.podBridge.queryFilter(claimNativeFilter)
227
224
  ]);
228
225
  // Create a map of claimed request IDs
229
226
  const claimedMap = new Map();
@@ -268,8 +265,7 @@ class PodBridgeTrackerClient {
268
265
  const tokens = deposits.map(d => d.token);
269
266
  const amounts = deposits.map(d => d.amount);
270
267
  const tos = deposits.map(d => d.to);
271
- const results = await this.destBridge.areRequestsProcessed(ids, tokens, amounts, tos);
272
- return results;
268
+ return await this.podBridge.areRequestsProcessed(ids, tokens, amounts, tos);
273
269
  }
274
270
  catch (error) {
275
271
  console.error('Batch check failed, falling back to individual checks:', error);
@@ -278,7 +274,7 @@ class PodBridgeTrackerClient {
278
274
  for (const deposit of deposits) {
279
275
  try {
280
276
  const hash = this.computeRequestHash(deposit.requestId, deposit.token, deposit.amount, deposit.to);
281
- const isProcessed = await this.destBridge.processedRequests(hash);
277
+ const isProcessed = await this.podBridge.processedRequests(hash);
282
278
  results.push(isProcessed);
283
279
  }
284
280
  catch (_a) {
@@ -299,5 +295,157 @@ class PodBridgeTrackerClient {
299
295
  computeRequestHash(id, token, amount, to) {
300
296
  return ethers_1.ethers.solidityPackedKeccak256(['uint256', 'address', 'uint256', 'address'], [id, token, amount, to]);
301
297
  }
298
+ /**
299
+ * Get certified log for a deposit transaction from POD
300
+ * This is required to claim tokens on Sepolia from POD deposits
301
+ * @param txHash Transaction hash of the deposit on POD
302
+ * @returns Certified log with attestations and merkle proof
303
+ */
304
+ async getDepositCertifiedLog(txHash) {
305
+ // Fetch the transaction receipt with POD metadata
306
+ const receipt = await this.podProvider.getTransactionReceipt(txHash);
307
+ if (!receipt) {
308
+ throw new Error(`Transaction receipt not found for hash: ${txHash}`);
309
+ }
310
+ if (!receipt.pod_metadata || !receipt.pod_metadata.attestations) {
311
+ throw new Error(`Transaction ${txHash} does not have POD metadata with attestations`);
312
+ }
313
+ if (receipt.logs.length === 0) {
314
+ throw new Error(`No logs found in transaction ${txHash}`);
315
+ }
316
+ // Find the Deposit or DepositNative event
317
+ const depositLog = receipt.logs.find(log => {
318
+ const topics = log.topics;
319
+ if (topics.length === 0)
320
+ return false;
321
+ const depositEventSig = ethers_1.ethers.id('Deposit(uint256,address,address,address,uint256,uint256,uint256)');
322
+ const depositNativeEventSig = ethers_1.ethers.id('DepositNative(uint256,address,address,uint256,uint256,uint256)');
323
+ return topics[0] === depositEventSig || topics[0] === depositNativeEventSig;
324
+ });
325
+ if (!depositLog) {
326
+ throw new Error(`No Deposit or DepositNative event found in transaction ${txHash}`);
327
+ }
328
+ // Compute receipt root (hash of receipt without pod_metadata)
329
+ const receiptRoot = this.computeReceiptRoot(receipt);
330
+ // Generate aggregate signature from attestations
331
+ const sortedAttestations = [...receipt.pod_metadata.attestations].sort((a, b) => a.timestamp - b.timestamp);
332
+ const aggregateSignature = this.aggregateSignatures(sortedAttestations);
333
+ const sortedTimestamps = sortedAttestations.map(att => BigInt(Math.floor(att.timestamp / 1000000))); // Convert microseconds to seconds
334
+ // Generate merkle proof for the log
335
+ const proof = this.generateMerkleProof(receipt.logs, parseInt(depositLog.logIndex));
336
+ // Compute leaf hash
337
+ const logHash = this.hashLog({
338
+ addr: depositLog.address,
339
+ topics: depositLog.topics,
340
+ data: depositLog.data
341
+ });
342
+ const leaf = this.hashLeaf(`log_hashes[${depositLog.logIndex}]`, logHash);
343
+ return {
344
+ log: {
345
+ addr: depositLog.address,
346
+ topics: depositLog.topics,
347
+ data: depositLog.data
348
+ },
349
+ logIndex: BigInt(depositLog.logIndex),
350
+ certificate: {
351
+ leaf,
352
+ certifiedReceipt: {
353
+ receiptRoot,
354
+ aggregateSignature,
355
+ sortedAttestationTimestamps: sortedTimestamps
356
+ },
357
+ proof: {
358
+ path: proof
359
+ }
360
+ }
361
+ };
362
+ }
363
+ /**
364
+ * Compute receipt root hash
365
+ * @private
366
+ */
367
+ computeReceiptRoot(receipt) {
368
+ // Create a simplified receipt object without pod_metadata for hashing
369
+ const logs = receipt.logs.map(log => ({
370
+ address: log.address,
371
+ topics: log.topics,
372
+ data: log.data
373
+ }));
374
+ // Receipt RLP encoding fields (simplified - matches POD's receipt structure)
375
+ const receiptData = ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(['uint8', 'uint256', 'bytes32', 'uint256', 'tuple(address,bytes32[],bytes)[]'], [
376
+ parseInt(receipt.status),
377
+ BigInt(receipt.cumulativeGasUsed),
378
+ receipt.logsBloom,
379
+ BigInt(receipt.gasUsed),
380
+ logs.map(log => [log.address, log.topics, log.data])
381
+ ]);
382
+ return ethers_1.ethers.keccak256(receiptData);
383
+ }
384
+ /**
385
+ * Aggregate signatures from attestations
386
+ * @private
387
+ */
388
+ aggregateSignatures(attestations) {
389
+ // Concatenate all signatures (r, s, v format)
390
+ const signatures = attestations.map(att => {
391
+ const r = att.signature.r.startsWith('0x') ? att.signature.r.slice(2) : att.signature.r;
392
+ const s = att.signature.s.startsWith('0x') ? att.signature.s.slice(2) : att.signature.s;
393
+ const v = att.signature.v.startsWith('0x') ? att.signature.v.slice(2) : att.signature.v;
394
+ return r + s + v.padStart(2, '0');
395
+ });
396
+ return '0x' + signatures.join('');
397
+ }
398
+ /**
399
+ * Hash a log entry
400
+ * @private
401
+ */
402
+ hashLog(log) {
403
+ return ethers_1.ethers.keccak256(ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(['address', 'bytes32[]', 'bytes'], [log.addr, log.topics, log.data]));
404
+ }
405
+ /**
406
+ * Hash a leaf for merkle tree
407
+ * @private
408
+ */
409
+ hashLeaf(key, value) {
410
+ return ethers_1.ethers.keccak256(ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(['bytes', 'bytes32'], [ethers_1.ethers.toUtf8Bytes(key), value]));
411
+ }
412
+ /**
413
+ * Generate merkle proof for a log at given index
414
+ * @private
415
+ */
416
+ generateMerkleProof(logs, logIndex) {
417
+ // Hash all logs
418
+ const logHashes = logs.map((log, idx) => this.hashLeaf(`log_hashes[${idx}]`, this.hashLog({
419
+ addr: log.address,
420
+ topics: log.topics,
421
+ data: log.data
422
+ })));
423
+ // Build merkle tree and generate proof
424
+ const proof = [];
425
+ let currentIndex = logIndex;
426
+ let currentLevel = [...logHashes];
427
+ while (currentLevel.length > 1) {
428
+ const nextLevel = [];
429
+ for (let i = 0; i < currentLevel.length; i += 2) {
430
+ if (i + 1 < currentLevel.length) {
431
+ // Pair exists
432
+ const left = currentLevel[i];
433
+ const right = currentLevel[i + 1];
434
+ // Add sibling to proof if current index is in this pair
435
+ if (i === currentIndex || i + 1 === currentIndex) {
436
+ proof.push(i === currentIndex ? right : left);
437
+ }
438
+ nextLevel.push(ethers_1.ethers.keccak256(ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(['bytes32', 'bytes32'], [left, right])));
439
+ }
440
+ else {
441
+ // Odd node, promote to next level
442
+ nextLevel.push(currentLevel[i]);
443
+ }
444
+ }
445
+ currentIndex = Math.floor(currentIndex / 2);
446
+ currentLevel = nextLevel;
447
+ }
448
+ return proof;
449
+ }
302
450
  }
303
451
  exports.PodBridgeTrackerClient = PodBridgeTrackerClient;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export { PodBridgeActionClient } from './clients/action/client';
1
+ export { PodToBridgedActionClient } from './clients/action/pod-to-bridged-client';
2
+ export { BridgedToPodActionClient } from './clients/action/bridged-to-pod-client';
2
3
  export { PodBridgeTrackerClient } from './clients/tracker/client';
3
4
  export { POD_BRIDGE_ABI } from './libs/abi/bridge.abi';
4
- export { PodBridgeConfig, BridgeRequest, BridgeRequestWithType, DepositType, UnsignedTransaction, CertifiedLog, } from './libs/types/pod-bridge.types';
5
+ export { PodBridgeConfig, BridgeRequest, BridgeRequestWithType, DepositType, UnsignedTransaction, CertifiedLog, PodAttestation, PodMetadata, PodTransactionReceipt, } from './libs/types/pod-bridge.types';
package/dist/index.js CHANGED
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DepositType = exports.POD_BRIDGE_ABI = exports.PodBridgeTrackerClient = exports.PodBridgeActionClient = void 0;
4
- var client_1 = require("./clients/action/client");
5
- Object.defineProperty(exports, "PodBridgeActionClient", { enumerable: true, get: function () { return client_1.PodBridgeActionClient; } });
6
- var client_2 = require("./clients/tracker/client");
7
- Object.defineProperty(exports, "PodBridgeTrackerClient", { enumerable: true, get: function () { return client_2.PodBridgeTrackerClient; } });
3
+ exports.DepositType = exports.POD_BRIDGE_ABI = exports.PodBridgeTrackerClient = exports.BridgedToPodActionClient = exports.PodToBridgedActionClient = void 0;
4
+ var pod_to_bridged_client_1 = require("./clients/action/pod-to-bridged-client");
5
+ Object.defineProperty(exports, "PodToBridgedActionClient", { enumerable: true, get: function () { return pod_to_bridged_client_1.PodToBridgedActionClient; } });
6
+ var bridged_to_pod_client_1 = require("./clients/action/bridged-to-pod-client");
7
+ Object.defineProperty(exports, "BridgedToPodActionClient", { enumerable: true, get: function () { return bridged_to_pod_client_1.BridgedToPodActionClient; } });
8
+ var client_1 = require("./clients/tracker/client");
9
+ Object.defineProperty(exports, "PodBridgeTrackerClient", { enumerable: true, get: function () { return client_1.PodBridgeTrackerClient; } });
8
10
  var bridge_abi_1 = require("./libs/abi/bridge.abi");
9
11
  Object.defineProperty(exports, "POD_BRIDGE_ABI", { enumerable: true, get: function () { return bridge_abi_1.POD_BRIDGE_ABI; } });
10
12
  var pod_bridge_types_1 = require("./libs/types/pod-bridge.types");
@@ -2,9 +2,22 @@ export interface PodBridgeChainConfig {
2
2
  rpcUrl: string;
3
3
  contractAddress: string;
4
4
  }
5
+ /**
6
+ * Configuration for the bridge
7
+ * * bridged: Configuration for the bridged chain. BridgeDepositWithdraw contract address
8
+ * * pod: Configuration for the POD chain. BridgeMintBurn contract address
9
+ */
5
10
  export interface PodBridgeConfig {
6
- source: PodBridgeChainConfig;
7
- destination: PodBridgeChainConfig;
11
+ bridged: PodBridgeChainConfig;
12
+ pod: PodBridgeChainConfig;
13
+ }
14
+ export interface PodBridgeActionsClientConfig {
15
+ bridged: {
16
+ contractAddress: string;
17
+ };
18
+ pod: {
19
+ contractAddress: string;
20
+ };
8
21
  }
9
22
  export interface BridgeRequest {
10
23
  requestId: string;
@@ -41,9 +54,56 @@ export interface CertifiedLog {
41
54
  topics: string[];
42
55
  data: string;
43
56
  };
44
- sigs: Array<{
57
+ logIndex: bigint | string;
58
+ certificate: {
59
+ leaf: string;
60
+ certifiedReceipt: {
61
+ receiptRoot: string;
62
+ aggregateSignature: string;
63
+ sortedAttestationTimestamps: bigint[] | string[];
64
+ };
65
+ proof: {
66
+ path: string[];
67
+ };
68
+ };
69
+ }
70
+ export interface PodAttestation {
71
+ public_key: string;
72
+ signature: {
45
73
  r: string;
46
74
  s: string;
47
- v: number;
75
+ v: string;
76
+ yParity: string;
77
+ };
78
+ timestamp: number;
79
+ }
80
+ export interface PodMetadata {
81
+ attestations: PodAttestation[];
82
+ }
83
+ export interface PodTransactionReceipt {
84
+ blockHash: string;
85
+ blockNumber: string;
86
+ contractAddress: string | null;
87
+ cumulativeGasUsed: string;
88
+ effectiveGasPrice: string;
89
+ from: string;
90
+ gasUsed: string;
91
+ logs: Array<{
92
+ address: string;
93
+ topics: string[];
94
+ data: string;
95
+ blockNumber: string;
96
+ transactionHash: string;
97
+ transactionIndex: string;
98
+ blockHash: string;
99
+ logIndex: string;
100
+ removed: boolean;
48
101
  }>;
102
+ logsBloom: string;
103
+ pod_metadata: PodMetadata;
104
+ status: string;
105
+ to: string;
106
+ transactionHash: string;
107
+ transactionIndex: string;
108
+ type: string;
49
109
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapforce/pod-bridge-sdk",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "SDK for interacting with Bridges between pod and other chains",
5
5
  "keywords": [
6
6
  "pod",