@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 +115 -156
- package/dist/clients/action/pod-to-source-chain-client.d.ts +20 -21
- package/dist/clients/action/pod-to-source-chain-client.js +25 -27
- package/dist/clients/action/source-chain-to-pod-client.d.ts +7 -6
- package/dist/clients/action/source-chain-to-pod-client.js +9 -8
- package/dist/clients/tracker/client.d.ts +5 -9
- package/dist/clients/tracker/client.js +12 -17
- package/dist/clients/tracker/pod-tracker.service.d.ts +4 -13
- package/dist/clients/tracker/pod-tracker.service.js +34 -31
- package/dist/clients/tracker/source-chain-tracker.service.d.ts +5 -10
- package/dist/clients/tracker/source-chain-tracker.service.js +25 -20
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -11
- package/dist/libs/abi/bridge.abi.d.ts +14 -6
- package/dist/libs/abi/bridge.abi.js +30 -20
- package/dist/libs/helpers/bridge-claim-proof.helper.d.ts +16 -0
- package/dist/libs/helpers/bridge-claim-proof.helper.js +27 -0
- package/dist/libs/helpers/convert-certified-log.helper.d.ts +2 -6
- package/dist/libs/helpers/convert-certified-log.helper.js +4 -8
- package/dist/libs/types/pod-bridge.types.d.ts +54 -17
- package/package.json +1 -1
- package/dist/libs/helpers/signature-recovery.helper.d.ts +0 -161
- package/dist/libs/helpers/signature-recovery.helper.js +0 -447
package/README.md
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
# Pod Bridge SDK
|
|
2
2
|
|
|
3
|
-
TypeScript SDK for bridging
|
|
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
|
|
9
|
-
Pod
|
|
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
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
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
|
|
20
|
-
- **
|
|
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
|
-
|
|
43
|
-
|
|
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...' //
|
|
58
|
+
contractAddress: '0x...' // BridgeDepositWithdraw on ETH
|
|
57
59
|
},
|
|
58
60
|
pod: {
|
|
59
|
-
contractAddress: '
|
|
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://
|
|
74
|
+
provider: new ethers.JsonRpcProvider('https://eth-mainnet.rpc.example'),
|
|
73
75
|
contractAddress: '0x...',
|
|
74
|
-
deploymentBlock:
|
|
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: '
|
|
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
|
|
88
|
+
### ETH -> Pod (Auto-claim)
|
|
87
89
|
|
|
88
|
-
Deposits on ETH are automatically claimed on Pod after block finalization
|
|
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: '
|
|
96
|
-
amount: ethers.
|
|
97
|
-
destinationWalletAddress: '0x...',
|
|
98
|
-
from: '0x...'
|
|
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
|
-
//
|
|
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
|
|
111
|
+
### Pod -> ETH (Claim with proof)
|
|
109
112
|
|
|
110
|
-
Deposits on Pod require
|
|
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
|
-
|
|
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: '
|
|
123
|
-
amount: ethers.
|
|
124
|
-
destinationWalletAddress: '0x...',
|
|
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
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
|
138
|
-
const
|
|
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
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
|
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('
|
|
175
|
-
console.log('
|
|
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
|
|
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
|
|
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
|
|
202
|
+
For Pod -> ETH deposits and claims.
|
|
210
203
|
|
|
211
204
|
```typescript
|
|
212
|
-
// Deposit
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
316
|
-
const address = addressFromPublicKey(uncompressedPubKey);
|
|
317
|
-
```
|
|
291
|
+
The bridge contracts emit different events per chain:
|
|
318
292
|
|
|
319
|
-
|
|
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
|
-
|
|
322
|
-
|
|
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
|
-
|
|
302
|
+
## ABIs
|
|
337
303
|
|
|
338
|
-
|
|
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
|
-
|
|
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
|
-
|
|
310
|
+
## Pod-specific Notes
|
|
353
311
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
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
|
-
*
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
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 (
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
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
|
|
16
|
+
private readonly podIface;
|
|
17
|
+
private readonly sourceChainIface;
|
|
20
18
|
constructor(config: PodBridgeActionsClientConfig);
|
|
21
19
|
/**
|
|
22
|
-
* Create unsigned transaction for depositing
|
|
20
|
+
* Create unsigned transaction for depositing tokens from Pod to ETH
|
|
23
21
|
*
|
|
24
22
|
* After deposit:
|
|
25
|
-
* -
|
|
26
|
-
* - Call claim() on ETH with
|
|
23
|
+
* - Call pod_getBridgeClaimProof(depositTxHash) on Pod RPC
|
|
24
|
+
* - Call claim() on ETH with the proof
|
|
27
25
|
*
|
|
28
|
-
* Note:
|
|
29
|
-
*
|
|
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
|
|
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
|
|
43
|
+
* Create unsigned transaction for claiming tokens on ETH (source chain)
|
|
45
44
|
*
|
|
46
|
-
* This is called after depositing on Pod and
|
|
47
|
-
*
|
|
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
|
|
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
|
-
*
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
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 (
|
|
17
|
-
* -
|
|
18
|
-
* -
|
|
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.
|
|
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
|
|
25
|
+
* Create unsigned transaction for depositing tokens from Pod to ETH
|
|
28
26
|
*
|
|
29
27
|
* After deposit:
|
|
30
|
-
* -
|
|
31
|
-
* - Call claim() on ETH with
|
|
28
|
+
* - Call pod_getBridgeClaimProof(depositTxHash) on Pod RPC
|
|
29
|
+
* - Call claim() on ETH with the proof
|
|
32
30
|
*
|
|
33
|
-
* Note:
|
|
34
|
-
*
|
|
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
|
|
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.
|
|
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
|
|
55
|
+
* Create unsigned transaction for claiming tokens on ETH (source chain)
|
|
57
56
|
*
|
|
58
|
-
* This is called after depositing on Pod and
|
|
59
|
-
*
|
|
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
|
|
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,
|
|
67
|
-
const data = this.
|
|
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
|
-
|
|
72
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
}
|