@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.
@@ -6,30 +6,30 @@ const bridge_abi_1 = require("../../libs/abi/bridge.abi");
6
6
  /**
7
7
  * SourceChainToPodActionClient - Handles ETH -> Pod bridging
8
8
  *
9
- * New architecture:
10
9
  * - User deposits ERC20 tokens on ETH (source chain)
11
- * - Balance is automatically added on Pod (~15 min on Sepolia, instant on Anvil)
10
+ * - Balance is automatically added on Pod after finalization
12
11
  * - NO claim transaction needed on Pod side (auto-claim)
13
- * - Only ERC20 tokens supported (wrap ETH to WETH first)
14
12
  */
15
13
  class SourceChainToPodActionClient {
16
14
  constructor(config) {
17
15
  this.config = config;
18
- this.iface = new ethers_1.Interface(bridge_abi_1.BRIDGE_ABI);
16
+ this.iface = new ethers_1.Interface(bridge_abi_1.SOURCE_CHAIN_BRIDGE_ABI);
19
17
  }
20
18
  /**
21
19
  * Create unsigned transaction for depositing ERC20 tokens from ETH to Pod
22
20
  *
23
21
  * After deposit:
24
- * - Wait for block finalization (~15 min on Sepolia, instant on Anvil)
22
+ * - Wait for block finalization
25
23
  * - Balance will be automatically added on Pod (no claim needed)
26
24
  *
27
- * Note: Native ETH is not supported. Wrap to WETH first.
28
25
  * Note: Token addresses differ between ETH and Pod chains.
26
+ * Note: For USDC-like tokens, use the token's decimals (e.g. parseUnits('1', 6)),
27
+ * not parseEther which assumes 18 decimals.
29
28
  *
30
29
  * @param args.token Token address on source chain (ETH) to deposit
31
- * @param args.amount Amount to deposit (in wei)
30
+ * @param args.amount Amount to deposit (in token's smallest unit)
32
31
  * @param args.destinationWalletAddress Recipient address on Pod
32
+ * @param args.permit Optional permit bytes for gasless approval (default '0x')
33
33
  * @param args.from Optional sender address
34
34
  * @returns Unsigned transaction template with encoded deposit call
35
35
  */
@@ -37,7 +37,8 @@ class SourceChainToPodActionClient {
37
37
  const data = this.iface.encodeFunctionData('deposit', [
38
38
  args.token,
39
39
  args.amount,
40
- args.destinationWalletAddress
40
+ args.destinationWalletAddress,
41
+ args.permit ?? '0x',
41
42
  ]);
42
43
  return {
43
44
  to: this.config.sourceChain.contractAddress,
@@ -6,7 +6,7 @@ import { PodBridgeConfig, BridgeRequest, BridgeRequestWithType } from "../../lib
6
6
  * to provide a unified view of bridge activity across both chains.
7
7
  *
8
8
  * Bridge Architecture:
9
- * - ETH -> Pod: deposits on ETH, AUTO-CLAIM on Pod (no claim needed)
9
+ * - ETH -> Pod: deposits on ETH, claimable on Pod once Sepolia block is finalized
10
10
  * - Pod -> ETH: deposits on Pod, claims on ETH with aggregated validator signatures
11
11
  * - Only ERC20 tokens supported (wrap ETH to WETH)
12
12
  *
@@ -15,7 +15,6 @@ import { PodBridgeConfig, BridgeRequest, BridgeRequestWithType } from "../../lib
15
15
  * - Claims release ERC20 tokens with validator signatures (Pod -> ETH direction)
16
16
  *
17
17
  * POD Chain:
18
- * - Auto-claim for ETH -> Pod deposits (instant finality)
19
18
  * - Deposits for Pod -> ETH direction
20
19
  */
21
20
  export declare class PodBridgeTrackerClient {
@@ -46,19 +45,17 @@ export declare class PodBridgeTrackerClient {
46
45
  /**
47
46
  * Check if deposits can be claimed
48
47
  *
49
- * New architecture:
50
- * - ETH -> Pod: AUTO-CLAIM on Pod, no manual claim needed (always returns false)
48
+ * - ETH -> Pod: Claimable once the Sepolia deposit block is finalized
51
49
  * - Pod -> ETH: Manual claim needed on ETH with aggregated signatures
52
50
  *
53
51
  * @param deposit The bridge request to check
54
- * @returns True if the deposit can be manually claimed (only Pod -> ETH direction)
52
+ * @returns True if the deposit can be claimed
55
53
  */
56
54
  canBeClaimed(deposit: BridgeRequest): Promise<boolean>;
57
55
  /**
58
56
  * Batch check claim status for multiple deposits
59
57
  *
60
- * New architecture:
61
- * - ETH -> Pod: AUTO-CLAIM on Pod (mark as claimed after finalization)
58
+ * - ETH -> Pod: isClaimed=false, isClaimable=true once Sepolia block is finalized
62
59
  * - Pod -> ETH: Check claim events on Source Chain
63
60
  *
64
61
  * @private
@@ -67,8 +64,7 @@ export declare class PodBridgeTrackerClient {
67
64
  /**
68
65
  * Batch check if multiple requests have been processed on-chain
69
66
  *
70
- * New architecture:
71
- * - ETH -> Pod: Auto-claimed after finalization
67
+ * - ETH -> Pod: Not auto-claimed; isClaimed reflects actual claim status
72
68
  * - Pod -> ETH: Check claim events on Source Chain
73
69
  *
74
70
  * @param deposits Array of deposits to check
@@ -11,7 +11,7 @@ const pod_tracker_service_1 = require("./pod-tracker.service");
11
11
  * to provide a unified view of bridge activity across both chains.
12
12
  *
13
13
  * Bridge Architecture:
14
- * - ETH -> Pod: deposits on ETH, AUTO-CLAIM on Pod (no claim needed)
14
+ * - ETH -> Pod: deposits on ETH, claimable on Pod once Sepolia block is finalized
15
15
  * - Pod -> ETH: deposits on Pod, claims on ETH with aggregated validator signatures
16
16
  * - Only ERC20 tokens supported (wrap ETH to WETH)
17
17
  *
@@ -20,7 +20,6 @@ const pod_tracker_service_1 = require("./pod-tracker.service");
20
20
  * - Claims release ERC20 tokens with validator signatures (Pod -> ETH direction)
21
21
  *
22
22
  * POD Chain:
23
- * - Auto-claim for ETH -> Pod deposits (instant finality)
24
23
  * - Deposits for Pod -> ETH direction
25
24
  */
26
25
  class PodBridgeTrackerClient {
@@ -107,18 +106,17 @@ class PodBridgeTrackerClient {
107
106
  /**
108
107
  * Check if deposits can be claimed
109
108
  *
110
- * New architecture:
111
- * - ETH -> Pod: AUTO-CLAIM on Pod, no manual claim needed (always returns false)
109
+ * - ETH -> Pod: Claimable once the Sepolia deposit block is finalized
112
110
  * - Pod -> ETH: Manual claim needed on ETH with aggregated signatures
113
111
  *
114
112
  * @param deposit The bridge request to check
115
- * @returns True if the deposit can be manually claimed (only Pod -> ETH direction)
113
+ * @returns True if the deposit can be claimed
116
114
  */
117
115
  async canBeClaimed(deposit) {
118
- // ETH -> Pod deposits have AUTO-CLAIM on Pod, no manual claim needed
119
116
  if (deposit.deposit.chain === pod_bridge_types_1.BridgeChain.SOURCE_CHAIN) {
120
- // Auto-claim on Pod - nothing to claim manually
121
- return false;
117
+ // ETH -> Pod: claimable once the deposit block is finalized on Sepolia
118
+ const isFinalized = await this.sourceChainTracker.isBlockFinalized(deposit.deposit.blockNumber);
119
+ return isFinalized && !deposit.isClaimed;
122
120
  }
123
121
  else {
124
122
  // POD -> ETH deposits need manual claim on ETH
@@ -129,8 +127,7 @@ class PodBridgeTrackerClient {
129
127
  /**
130
128
  * Batch check claim status for multiple deposits
131
129
  *
132
- * New architecture:
133
- * - ETH -> Pod: AUTO-CLAIM on Pod (mark as claimed after finalization)
130
+ * - ETH -> Pod: isClaimed=false, isClaimable=true once Sepolia block is finalized
134
131
  * - Pod -> ETH: Check claim events on Source Chain
135
132
  *
136
133
  * @private
@@ -170,6 +167,7 @@ class PodBridgeTrackerClient {
170
167
  }
171
168
  else {
172
169
  // Pod -> ETH: Check manual claim on Source Chain
170
+ // Claim event's txHash field = deposit's requestId (not deposit's txHash)
173
171
  const claimInfo = sourceChainClaimEvents.get(depositData.requestId);
174
172
  if (claimInfo) {
175
173
  depositData.isClaimed = true;
@@ -200,8 +198,7 @@ class PodBridgeTrackerClient {
200
198
  /**
201
199
  * Batch check if multiple requests have been processed on-chain
202
200
  *
203
- * New architecture:
204
- * - ETH -> Pod: Auto-claimed after finalization
201
+ * - ETH -> Pod: Not auto-claimed; isClaimed reflects actual claim status
205
202
  * - Pod -> ETH: Check claim events on Source Chain
206
203
  *
207
204
  * @param deposits Array of deposits to check
@@ -210,8 +207,6 @@ class PodBridgeTrackerClient {
210
207
  async areRequestsProcessed(deposits) {
211
208
  if (deposits.length === 0)
212
209
  return [];
213
- // Get finalized block for ETH -> Pod auto-claim check
214
- const finalizedBlock = await this.sourceChainTracker.getFinalizedBlockNumber();
215
210
  // Group deposits by origin chain
216
211
  const podDeposits = deposits.filter(d => d.deposit.chain === pod_bridge_types_1.BridgeChain.POD);
217
212
  // Check claims on Source Chain for Pod -> ETH deposits
@@ -220,11 +215,11 @@ class PodBridgeTrackerClient {
220
215
  : new Map();
221
216
  return deposits.map(d => {
222
217
  if (d.deposit.chain === pod_bridge_types_1.BridgeChain.SOURCE_CHAIN) {
223
- // ETH -> Pod: Auto-claimed once finalized
224
- return d.deposit.blockNumber <= finalizedBlock;
218
+ // ETH -> Pod: isClaimed is set during updateClaimStatus
219
+ return d.isClaimed;
225
220
  }
226
221
  else {
227
- // Pod -> ETH: Check claim event on Source Chain
222
+ // Pod -> ETH: Claim event's txHash field = deposit's requestId
228
223
  return sourceChainClaims.has(d.requestId);
229
224
  }
230
225
  });
@@ -2,21 +2,15 @@ import { BridgeRequest, PodBridgeChainConfig } from '../../libs/types/pod-bridge
2
2
  /**
3
3
  * PodTrackerService - Handles tracking on the POD Chain
4
4
  *
5
- * New architecture:
6
- * - ETH -> Pod: auto-claim on Pod (no claim tracking needed on Pod)
7
- * - Pod -> ETH: deposits are made here, claimed on ETH
8
- * - Only ERC20 tokens supported (no native)
9
- *
10
5
  * Responsibilities:
11
6
  * - Fetch deposits made on POD (Pod -> ETH direction)
12
7
  *
13
- * Note: POD uses a single-block architecture where blocks are essentially
14
- * timestamps. The chain has instant finality.
8
+ * Note: POD returns logs with blockNumber: null which ethers.js can't parse.
9
+ * We use raw eth_getLogs RPC calls and parse logs manually.
15
10
  */
16
11
  export declare class PodTrackerService {
17
12
  private readonly config;
18
13
  private readonly provider;
19
- private readonly bridge;
20
14
  private readonly iface;
21
15
  private chainId;
22
16
  constructor(config: PodBridgeChainConfig);
@@ -24,18 +18,15 @@ export declare class PodTrackerService {
24
18
  ensureChainId(): Promise<void>;
25
19
  /**
26
20
  * Get deposits sent by an address on POD
27
- * Note: POD has a single block, so blockNumber is essentially a timestamp
28
21
  */
29
22
  getDepositsSentBy(address: string): Promise<BridgeRequest[]>;
30
23
  /**
31
24
  * Get deposits received by an address on POD
32
- * Note: POD has a single block, so blockNumber is essentially a timestamp
33
25
  */
34
26
  getDepositsReceivedBy(address: string): Promise<BridgeRequest[]>;
35
27
  /**
36
- * Private method to fetch deposits from POD
37
- * POD uses a single-block architecture where blocks are essentially timestamps
38
- * Event: Deposit(bytes32 indexed id, address indexed from, address indexed to, address token, uint256 amount)
28
+ * Fetch deposits from POD using raw eth_getLogs RPC.
29
+ * Pod returns logs with blockNumber: null, so we can't use ethers queryFilter.
39
30
  */
40
31
  private getDeposits;
41
32
  }
@@ -7,24 +7,18 @@ const bridge_abi_1 = require("../../libs/abi/bridge.abi");
7
7
  /**
8
8
  * PodTrackerService - Handles tracking on the POD Chain
9
9
  *
10
- * New architecture:
11
- * - ETH -> Pod: auto-claim on Pod (no claim tracking needed on Pod)
12
- * - Pod -> ETH: deposits are made here, claimed on ETH
13
- * - Only ERC20 tokens supported (no native)
14
- *
15
10
  * Responsibilities:
16
11
  * - Fetch deposits made on POD (Pod -> ETH direction)
17
12
  *
18
- * Note: POD uses a single-block architecture where blocks are essentially
19
- * timestamps. The chain has instant finality.
13
+ * Note: POD returns logs with blockNumber: null which ethers.js can't parse.
14
+ * We use raw eth_getLogs RPC calls and parse logs manually.
20
15
  */
21
16
  class PodTrackerService {
22
17
  constructor(config) {
23
18
  this.config = config;
24
19
  this.chainId = null;
25
20
  this.provider = config.provider;
26
- this.bridge = new ethers_1.Contract(config.contractAddress, bridge_abi_1.BRIDGE_ABI, this.provider);
27
- this.iface = new ethers_1.Interface(bridge_abi_1.BRIDGE_ABI);
21
+ this.iface = new ethers_1.Interface(bridge_abi_1.POD_BRIDGE_ABI);
28
22
  this.initChainId();
29
23
  }
30
24
  async initChainId() {
@@ -43,43 +37,52 @@ class PodTrackerService {
43
37
  }
44
38
  /**
45
39
  * Get deposits sent by an address on POD
46
- * Note: POD has a single block, so blockNumber is essentially a timestamp
47
40
  */
48
41
  async getDepositsSentBy(address) {
49
42
  // Filter by 'from' (second indexed param): Deposit(id, from, to, token, amount)
50
- return this.getDeposits({
51
- depositEventFilter: [null, address, null]
52
- });
43
+ const fromTopic = ethers_1.ethers.zeroPadValue(address, 32);
44
+ return this.getDeposits([null, fromTopic, null]);
53
45
  }
54
46
  /**
55
47
  * Get deposits received by an address on POD
56
- * Note: POD has a single block, so blockNumber is essentially a timestamp
57
48
  */
58
49
  async getDepositsReceivedBy(address) {
59
50
  // Filter by 'to' (third indexed param): Deposit(id, from, to, token, amount)
60
- return this.getDeposits({
61
- depositEventFilter: [null, null, address]
62
- });
51
+ const toTopic = ethers_1.ethers.zeroPadValue(address, 32);
52
+ return this.getDeposits([null, null, toTopic]);
63
53
  }
64
54
  /**
65
- * Private method to fetch deposits from POD
66
- * POD uses a single-block architecture where blocks are essentially timestamps
67
- * Event: Deposit(bytes32 indexed id, address indexed from, address indexed to, address token, uint256 amount)
55
+ * Fetch deposits from POD using raw eth_getLogs RPC.
56
+ * Pod returns logs with blockNumber: null, so we can't use ethers queryFilter.
68
57
  */
69
- async getDeposits(options) {
58
+ async getDeposits(topicFilters) {
70
59
  const deposits = [];
71
- // Event: Deposit(bytes32 indexed id, address indexed from, address indexed to, address token, uint256 amount)
72
- const depositFilter = this.bridge.filters.Deposit(...options.depositEventFilter);
73
- const depositLogs = await this.bridge.queryFilter(depositFilter);
74
- // Process deposits
75
- for (const log of depositLogs) {
60
+ // Deposit event topic
61
+ const depositEventTopic = this.iface.getEvent('Deposit').topicHash;
62
+ // Build topics array: [eventSig, ...filters]
63
+ const topics = [depositEventTopic, ...topicFilters];
64
+ // Use raw RPC to avoid ethers.js blockNumber validation
65
+ const rpcProvider = this.provider;
66
+ const rawLogs = await rpcProvider.send('eth_getLogs', [{
67
+ address: this.config.contractAddress,
68
+ topics,
69
+ fromBlock: 'earliest',
70
+ toBlock: 'latest',
71
+ }]);
72
+ // Log-level blockNumber is null/0x1 on Pod, but receipt-level blockNumber
73
+ // contains the real timestamp. Fetch receipts in parallel.
74
+ const receiptPromises = rawLogs.map(log => rpcProvider.send('eth_getTransactionReceipt', [log.transactionHash]));
75
+ const receipts = await Promise.all(receiptPromises);
76
+ for (let i = 0; i < rawLogs.length; i++) {
77
+ const log = rawLogs[i];
78
+ const receipt = receipts[i];
76
79
  const parsed = this.iface.parseLog({
77
- topics: [...log.topics],
80
+ topics: log.topics,
78
81
  data: log.data
79
82
  });
80
83
  if (parsed) {
81
- // Get block for timestamp
82
- const block = await this.provider.getBlock(log.blockNumber);
84
+ // Receipt blockNumber on Pod is a Unix timestamp in hex (e.g. 0x69983FE1 -> 1771585505)
85
+ const timestamp = receipt?.blockNumber ? parseInt(receipt.blockNumber, 16) : 0;
83
86
  deposits.push({
84
87
  requestId: parsed.args.id.toString(),
85
88
  deposit: {
@@ -90,8 +93,8 @@ class PodTrackerService {
90
93
  token: parsed.args.token,
91
94
  amount: parsed.args.amount.toString(),
92
95
  chainId: this.chainId,
93
- blockNumber: log.blockNumber, // On POD, this is essentially a timestamp
94
- timestamp: block ? Number(block.timestamp) : 0
96
+ blockNumber: timestamp,
97
+ timestamp,
95
98
  },
96
99
  isClaimed: false,
97
100
  isClaimable: false
@@ -1,11 +1,6 @@
1
1
  import { BridgeRequest, BridgeChain, PodBridgeChainConfig } from '../../libs/types/pod-bridge.types';
2
2
  /**
3
- * SourceChainTrackerService - Handles tracking on the Source Chain (e.g., Sepolia/ETH)
4
- *
5
- * New architecture:
6
- * - ETH -> Pod: deposits are made here, auto-claimed on Pod
7
- * - Pod -> ETH: claims are made here with aggregated validator signatures
8
- * - Only ERC20 tokens supported (no native)
3
+ * SourceChainTrackerService - Handles tracking on the Source Chain (e.g., ETH Mainnet)
9
4
  *
10
5
  * Responsibilities:
11
6
  * - Fetch deposits made on Source Chain (ETH -> Pod direction)
@@ -34,13 +29,13 @@ export declare class SourceChainTrackerService {
34
29
  private getDeposits;
35
30
  /**
36
31
  * Get claim events that occurred ON Source Chain
37
- * These are claims of POD deposits (POD Source Chain direction)
38
- * Event: Claim(bytes32 indexed id, address indexed to, address token, uint256 amount)
32
+ * These are claims of POD deposits (POD -> Source Chain direction)
33
+ * Event: Claim(bytes32 indexed txHash, address token, address mirrorToken, uint256 amount, address indexed to)
39
34
  *
40
- * Pod Deposit.id = ETH Claim.id - used to track if deposit was claimed
35
+ * Pod deposit.txHash = ETH Claim.txHash - used to track if deposit was claimed
41
36
  *
42
37
  * @param deposits The POD deposits to check for claims
43
- * @returns Map of requestId to claim information
38
+ * @returns Map of deposit txHash to claim information
44
39
  */
45
40
  getClaimEvents(deposits: BridgeRequest[]): Promise<Map<string, {
46
41
  chain: BridgeChain;
@@ -5,12 +5,7 @@ const ethers_1 = require("ethers");
5
5
  const pod_bridge_types_1 = require("../../libs/types/pod-bridge.types");
6
6
  const bridge_abi_1 = require("../../libs/abi/bridge.abi");
7
7
  /**
8
- * SourceChainTrackerService - Handles tracking on the Source Chain (e.g., Sepolia/ETH)
9
- *
10
- * New architecture:
11
- * - ETH -> Pod: deposits are made here, auto-claimed on Pod
12
- * - Pod -> ETH: claims are made here with aggregated validator signatures
13
- * - Only ERC20 tokens supported (no native)
8
+ * SourceChainTrackerService - Handles tracking on the Source Chain (e.g., ETH Mainnet)
14
9
  *
15
10
  * Responsibilities:
16
11
  * - Fetch deposits made on Source Chain (ETH -> Pod direction)
@@ -21,8 +16,8 @@ class SourceChainTrackerService {
21
16
  this.config = config;
22
17
  this.chainId = null;
23
18
  this.provider = config.provider;
24
- this.bridge = new ethers_1.Contract(config.contractAddress, bridge_abi_1.BRIDGE_ABI, this.provider);
25
- this.iface = new ethers_1.Interface(bridge_abi_1.BRIDGE_ABI);
19
+ this.bridge = new ethers_1.Contract(config.contractAddress, bridge_abi_1.SOURCE_CHAIN_BRIDGE_ABI, this.provider);
20
+ this.iface = new ethers_1.Interface(bridge_abi_1.SOURCE_CHAIN_BRIDGE_ABI);
26
21
  this.initChainId();
27
22
  }
28
23
  async initChainId() {
@@ -61,7 +56,7 @@ class SourceChainTrackerService {
61
56
  const BLOCK_BATCH_SIZE = 10000;
62
57
  for (let start = startBlock; start <= currentBlock; start += BLOCK_BATCH_SIZE) {
63
58
  const end = Math.min(start + BLOCK_BATCH_SIZE - 1, currentBlock);
64
- // Event: Deposit(bytes32 indexed id, address indexed from, address indexed to, address token, uint256 amount)
59
+ // Event: Deposit(uint256 indexed id, address indexed from, address indexed to, address token, uint256 amount)
65
60
  const depositFilter = this.bridge.filters.Deposit(...options.depositEventFilter);
66
61
  const depositLogs = await this.bridge.queryFilter(depositFilter, start, end);
67
62
  if (start + BLOCK_BATCH_SIZE <= currentBlock) {
@@ -99,22 +94,32 @@ class SourceChainTrackerService {
99
94
  }
100
95
  /**
101
96
  * Get claim events that occurred ON Source Chain
102
- * These are claims of POD deposits (POD Source Chain direction)
103
- * Event: Claim(bytes32 indexed id, address indexed to, address token, uint256 amount)
97
+ * These are claims of POD deposits (POD -> Source Chain direction)
98
+ * Event: Claim(bytes32 indexed txHash, address token, address mirrorToken, uint256 amount, address indexed to)
104
99
  *
105
- * Pod Deposit.id = ETH Claim.id - used to track if deposit was claimed
100
+ * Pod deposit.txHash = ETH Claim.txHash - used to track if deposit was claimed
106
101
  *
107
102
  * @param deposits The POD deposits to check for claims
108
- * @returns Map of requestId to claim information
103
+ * @returns Map of deposit txHash to claim information
109
104
  */
110
105
  async getClaimEvents(deposits) {
111
106
  const uniqueRecipients = [...new Set(deposits.map(d => d.deposit.destination))];
112
107
  const allClaimLogs = [];
108
+ const startBlock = this.config.deploymentBlock ?? 0;
109
+ const currentBlock = await this.provider.getBlockNumber();
110
+ const BLOCK_BATCH_SIZE = 10000;
113
111
  for (const recipient of uniqueRecipients) {
114
- // Event: Claim(bytes32 indexed id, address indexed to, address token, uint256 amount)
115
- const claimFilter = this.bridge.filters.Claim(null, recipient);
116
- const claimLogs = await this.bridge.queryFilter(claimFilter);
117
- allClaimLogs.push(...claimLogs);
112
+ // Event: Claim(bytes32 indexed txHash, address token, address mirrorToken, uint256 amount, address indexed to)
113
+ // Must pass null for all non-indexed params (token, mirrorToken, amount) to reach 'to'
114
+ const claimFilter = this.bridge.filters.Claim(null, null, null, null, recipient);
115
+ for (let start = startBlock; start <= currentBlock; start += BLOCK_BATCH_SIZE) {
116
+ const end = Math.min(start + BLOCK_BATCH_SIZE - 1, currentBlock);
117
+ const claimLogs = await this.bridge.queryFilter(claimFilter, start, end);
118
+ allClaimLogs.push(...claimLogs);
119
+ if (start + BLOCK_BATCH_SIZE <= currentBlock) {
120
+ await new Promise(resolve => setTimeout(resolve, 100));
121
+ }
122
+ }
118
123
  }
119
124
  console.log(`[SourceChain] Found ${allClaimLogs.length} claims`);
120
125
  const claimedMap = new Map();
@@ -126,8 +131,8 @@ class SourceChainTrackerService {
126
131
  if (parsed) {
127
132
  // Get block for timestamp
128
133
  const block = await this.provider.getBlock(log.blockNumber);
129
- // Pod Deposit.id = ETH Claim.id
130
- claimedMap.set(parsed.args.id.toString(), {
134
+ // Pod deposit.txHash = ETH Claim.txHash
135
+ claimedMap.set(parsed.args.txHash, {
131
136
  chain: pod_bridge_types_1.BridgeChain.SOURCE_CHAIN,
132
137
  txHash: log.transactionHash,
133
138
  timestamp: block ? Number(block.timestamp) : 0,
@@ -154,7 +159,7 @@ class SourceChainTrackerService {
154
159
  }
155
160
  // Fallback: Use manual calculation if RPC doesn't support finalized tag
156
161
  const currentBlock = await this.provider.getBlockNumber();
157
- return currentBlock - 64; // 2 epochs (32 x 2 blocks) ~15 minutes on Sepolia
162
+ return currentBlock - 64; // 2 epochs (32 x 2 blocks) ~15 minutes
158
163
  }
159
164
  /**
160
165
  * Check if a block is finalized
package/dist/index.d.ts CHANGED
@@ -2,5 +2,5 @@ export { PodToSourceChainActionClient } from './clients/action/pod-to-source-cha
2
2
  export { SourceChainToPodActionClient } from './clients/action/source-chain-to-pod-client';
3
3
  export { PodBridgeTrackerClient } from './clients/tracker/client';
4
4
  export { BRIDGE_ABI, POD_BRIDGE_ABI, SOURCE_CHAIN_BRIDGE_ABI, } from './libs/abi/bridge.abi';
5
- export { recoverSignature65B, recoverAggregatedSignatures65B, computeDepositTxHash, extractAggregatedSignatures, extractSignatureInfo, addressFromPublicKey, parseDerSignature, recoverSignatureWithoutPubkey, extractAggregatedSignaturesWithValidators } from './libs/helpers/signature-recovery.helper';
6
- export { PodBridgeConfig, BridgeRequest, BridgeRequestWithType, BridgeChain, DepositType, UnsignedTransaction, ClaimProofData, PodBridgeActionsClientConfig, PodBridgeChainConfig, } from './libs/types/pod-bridge.types';
5
+ export { getBridgeClaimProof, } from './libs/helpers/bridge-claim-proof.helper';
6
+ export { PodBridgeConfig, BridgeRequest, BridgeRequestWithType, BridgeChain, DepositType, UnsignedTransaction, ClaimProofData, BridgeClaimProofResponse, PodBridgeActionsClientConfig, PodBridgeChainConfig, } from './libs/types/pod-bridge.types';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DepositType = exports.BridgeChain = exports.extractAggregatedSignaturesWithValidators = exports.recoverSignatureWithoutPubkey = exports.parseDerSignature = exports.addressFromPublicKey = exports.extractSignatureInfo = exports.extractAggregatedSignatures = exports.computeDepositTxHash = exports.recoverAggregatedSignatures65B = exports.recoverSignature65B = exports.SOURCE_CHAIN_BRIDGE_ABI = exports.POD_BRIDGE_ABI = exports.BRIDGE_ABI = exports.PodBridgeTrackerClient = exports.SourceChainToPodActionClient = exports.PodToSourceChainActionClient = void 0;
3
+ exports.DepositType = exports.BridgeChain = exports.getBridgeClaimProof = exports.SOURCE_CHAIN_BRIDGE_ABI = exports.POD_BRIDGE_ABI = exports.BRIDGE_ABI = exports.PodBridgeTrackerClient = exports.SourceChainToPodActionClient = exports.PodToSourceChainActionClient = void 0;
4
4
  var pod_to_source_chain_client_1 = require("./clients/action/pod-to-source-chain-client");
5
5
  Object.defineProperty(exports, "PodToSourceChainActionClient", { enumerable: true, get: function () { return pod_to_source_chain_client_1.PodToSourceChainActionClient; } });
6
6
  var source_chain_to_pod_client_1 = require("./clients/action/source-chain-to-pod-client");
@@ -11,16 +11,8 @@ var bridge_abi_1 = require("./libs/abi/bridge.abi");
11
11
  Object.defineProperty(exports, "BRIDGE_ABI", { enumerable: true, get: function () { return bridge_abi_1.BRIDGE_ABI; } });
12
12
  Object.defineProperty(exports, "POD_BRIDGE_ABI", { enumerable: true, get: function () { return bridge_abi_1.POD_BRIDGE_ABI; } });
13
13
  Object.defineProperty(exports, "SOURCE_CHAIN_BRIDGE_ABI", { enumerable: true, get: function () { return bridge_abi_1.SOURCE_CHAIN_BRIDGE_ABI; } });
14
- var signature_recovery_helper_1 = require("./libs/helpers/signature-recovery.helper");
15
- Object.defineProperty(exports, "recoverSignature65B", { enumerable: true, get: function () { return signature_recovery_helper_1.recoverSignature65B; } });
16
- Object.defineProperty(exports, "recoverAggregatedSignatures65B", { enumerable: true, get: function () { return signature_recovery_helper_1.recoverAggregatedSignatures65B; } });
17
- Object.defineProperty(exports, "computeDepositTxHash", { enumerable: true, get: function () { return signature_recovery_helper_1.computeDepositTxHash; } });
18
- Object.defineProperty(exports, "extractAggregatedSignatures", { enumerable: true, get: function () { return signature_recovery_helper_1.extractAggregatedSignatures; } });
19
- Object.defineProperty(exports, "extractSignatureInfo", { enumerable: true, get: function () { return signature_recovery_helper_1.extractSignatureInfo; } });
20
- Object.defineProperty(exports, "addressFromPublicKey", { enumerable: true, get: function () { return signature_recovery_helper_1.addressFromPublicKey; } });
21
- Object.defineProperty(exports, "parseDerSignature", { enumerable: true, get: function () { return signature_recovery_helper_1.parseDerSignature; } });
22
- Object.defineProperty(exports, "recoverSignatureWithoutPubkey", { enumerable: true, get: function () { return signature_recovery_helper_1.recoverSignatureWithoutPubkey; } });
23
- Object.defineProperty(exports, "extractAggregatedSignaturesWithValidators", { enumerable: true, get: function () { return signature_recovery_helper_1.extractAggregatedSignaturesWithValidators; } });
14
+ var bridge_claim_proof_helper_1 = require("./libs/helpers/bridge-claim-proof.helper");
15
+ Object.defineProperty(exports, "getBridgeClaimProof", { enumerable: true, get: function () { return bridge_claim_proof_helper_1.getBridgeClaimProof; } });
24
16
  var pod_bridge_types_1 = require("./libs/types/pod-bridge.types");
25
17
  Object.defineProperty(exports, "BridgeChain", { enumerable: true, get: function () { return pod_bridge_types_1.BridgeChain; } });
26
18
  Object.defineProperty(exports, "DepositType", { enumerable: true, get: function () { return pod_bridge_types_1.DepositType; } });
@@ -1,10 +1,18 @@
1
1
  /**
2
- * ABI for Bridge contract on Source Chain (ETH/Sepolia)
3
- * New architecture:
4
- * - ETH -> Pod: deposit on ETH, auto-claim on Pod (no claim needed)
5
- * - Pod -> ETH: deposit on Pod, claim on ETH with aggregated validator signatures
6
- * - Only ERC20 tokens supported (no native ETH - must wrap to WETH)
2
+ * ABI for Bridge contract on Source Chain (ETH/Mainnet)
3
+ *
4
+ * ETH -> Pod: deposit on ETH (4-param with permit), auto-claim on Pod
5
+ * Pod -> ETH: deposit on Pod, claim on ETH with proof from pod_getBridgeClaimProof RPC
6
+ *
7
+ * Note: Pod and ETH bridge contracts have DIFFERENT event signatures:
8
+ * - ETH Deposit: uint256 indexed id (topic 0x71894900...)
9
+ * - Pod Deposit: bytes32 indexed id (topic 0x980e6de4...)
7
10
  */
8
- export declare const BRIDGE_ABI: string[];
9
11
  export declare const SOURCE_CHAIN_BRIDGE_ABI: string[];
12
+ /**
13
+ * ABI for Bridge system contract on Pod chain.
14
+ * Pod uses bytes32 indexed id in Deposit events (different from ETH's uint256).
15
+ * Pod deposit is 3-param (no permit).
16
+ */
10
17
  export declare const POD_BRIDGE_ABI: string[];
18
+ export declare const BRIDGE_ABI: string[];
@@ -1,29 +1,39 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.POD_BRIDGE_ABI = exports.SOURCE_CHAIN_BRIDGE_ABI = exports.BRIDGE_ABI = void 0;
3
+ exports.BRIDGE_ABI = exports.POD_BRIDGE_ABI = exports.SOURCE_CHAIN_BRIDGE_ABI = void 0;
4
4
  /**
5
- * ABI for Bridge contract on Source Chain (ETH/Sepolia)
6
- * New architecture:
7
- * - ETH -> Pod: deposit on ETH, auto-claim on Pod (no claim needed)
8
- * - Pod -> ETH: deposit on Pod, claim on ETH with aggregated validator signatures
9
- * - Only ERC20 tokens supported (no native ETH - must wrap to WETH)
5
+ * ABI for Bridge contract on Source Chain (ETH/Mainnet)
6
+ *
7
+ * ETH -> Pod: deposit on ETH (4-param with permit), auto-claim on Pod
8
+ * Pod -> ETH: deposit on Pod, claim on ETH with proof from pod_getBridgeClaimProof RPC
9
+ *
10
+ * Note: Pod and ETH bridge contracts have DIFFERENT event signatures:
11
+ * - ETH Deposit: uint256 indexed id (topic 0x71894900...)
12
+ * - Pod Deposit: bytes32 indexed id (topic 0x980e6de4...)
10
13
  */
11
- exports.BRIDGE_ABI = [
14
+ exports.SOURCE_CHAIN_BRIDGE_ABI = [
12
15
  // Events
13
- "event Deposit(bytes32 indexed id, address indexed from, address indexed to, address token, uint256 amount)",
14
- "event Claim(bytes32 indexed id, address indexed to, address token, uint256 amount)",
15
- // Deposit function (ERC20 only)
16
- "function deposit(address token, uint256 amount, address to) returns (bytes32)",
17
- // Claim function with aggregated validator signatures
18
- "function claim(address token, uint256 amount, address to, uint64 committeeEpoch, bytes aggregatedSignatures, bytes proof)",
16
+ "event Deposit(uint256 indexed id, address indexed from, address indexed to, address token, uint256 amount)",
17
+ "event Claim(bytes32 indexed txHash, address token, address mirrorToken, uint256 amount, address indexed to)",
18
+ // Deposit function (ERC20, with optional permit bytes)
19
+ "function deposit(address token, uint256 amount, address to, bytes permit) returns (uint256)",
20
+ // Claim function with proof from pod_getBridgeClaimProof
21
+ "function claim(address token, uint256 amount, address to, bytes proof, bytes auxTxSuffix)",
19
22
  // View functions
20
23
  "function processedRequests(bytes32) view returns (bool)",
21
- "function BRIDGE_CONTRACT() view returns (address)",
22
- "function DOMAIN_SEPARATOR() view returns (bytes32)",
23
- "function tokenData(address) view returns (uint256 minAmount, uint256 depositLimit, uint256 claimLimit, tuple(uint256 consumed, uint256 lastUpdated) depositUsage, tuple(uint256 consumed, uint256 lastUpdated) claimUsage, address mirrorToken)",
24
- "function whitelistedTokens(uint256) view returns (address)",
24
+ "function tokenData(address) view returns (uint256, uint256, uint256, tuple(uint256, uint256), tuple(uint256, uint256), address)",
25
25
  "function depositIndex() view returns (uint256)",
26
26
  ];
27
- // Legacy alias for backwards compatibility
28
- exports.SOURCE_CHAIN_BRIDGE_ABI = exports.BRIDGE_ABI;
29
- exports.POD_BRIDGE_ABI = exports.BRIDGE_ABI;
27
+ /**
28
+ * ABI for Bridge system contract on Pod chain.
29
+ * Pod uses bytes32 indexed id in Deposit events (different from ETH's uint256).
30
+ * Pod deposit is 3-param (no permit).
31
+ */
32
+ exports.POD_BRIDGE_ABI = [
33
+ // Events
34
+ "event Deposit(bytes32 indexed id, address indexed from, address indexed to, address token, uint256 amount)",
35
+ // Deposit function (3-param, no permit)
36
+ "function deposit(address token, uint256 amount, address to)",
37
+ ];
38
+ // Backward compatibility alias
39
+ exports.BRIDGE_ABI = exports.SOURCE_CHAIN_BRIDGE_ABI;
@@ -0,0 +1,16 @@
1
+ import { JsonRpcProvider } from 'ethers';
2
+ /**
3
+ * Fetch bridge claim proof from Pod RPC.
4
+ *
5
+ * Calls the `pod_getBridgeClaimProof` RPC method with the deposit transaction hash
6
+ * and returns the proof data formatted for use with the ETH bridge claim function.
7
+ *
8
+ * @param podProvider A JsonRpcProvider connected to the Pod RPC
9
+ * @param depositTxHash The deposit transaction hash on Pod
10
+ * @returns Formatted proof data ready for the claim call
11
+ */
12
+ export declare function getBridgeClaimProof(podProvider: JsonRpcProvider, depositTxHash: string): Promise<{
13
+ proof: string;
14
+ committeeEpoch: number;
15
+ auxTxSuffix: string;
16
+ }>;