@tapforce/pod-bridge-sdk 1.2.3 → 1.2.4
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 +71 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -110,6 +110,11 @@ const receipt = await tx.wait();
|
|
|
110
110
|
Deposits on Pod require manual claim on ETH with aggregated validator signatures.
|
|
111
111
|
|
|
112
112
|
```typescript
|
|
113
|
+
import {
|
|
114
|
+
PodToSourceChainActionClient,
|
|
115
|
+
extractAggregatedSignaturesWithValidators
|
|
116
|
+
} from '@tapforce/pod-bridge-sdk';
|
|
117
|
+
|
|
113
118
|
const client = new PodToSourceChainActionClient(actionConfig);
|
|
114
119
|
|
|
115
120
|
// Step 1: Deposit on Pod
|
|
@@ -123,17 +128,26 @@ const depositTx = client.deposit({
|
|
|
123
128
|
const tx = await podSigner.sendTransaction(depositTx);
|
|
124
129
|
const receipt = await tx.wait();
|
|
125
130
|
|
|
126
|
-
// Step 2: Get
|
|
127
|
-
|
|
131
|
+
// Step 2: Get the receipt with validator signatures
|
|
132
|
+
const podReceipt = await podProvider.send('eth_getTransactionReceipt', [tx.hash]);
|
|
133
|
+
|
|
134
|
+
// Step 3: Get committee for v-value recovery
|
|
135
|
+
const committee = await podProvider.send('pod_getCommittee', {});
|
|
128
136
|
|
|
129
|
-
// Step
|
|
137
|
+
// Step 4: Extract aggregated signatures (65-byte format with correct v-values)
|
|
138
|
+
const aggregatedSignatures = extractAggregatedSignaturesWithValidators(
|
|
139
|
+
podReceipt,
|
|
140
|
+
committee.validators // [[0, "02..."], [1, "03..."], ...] compressed pubkeys
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// Step 5: Claim on ETH
|
|
130
144
|
const claimTx = client.claim({
|
|
131
145
|
claimData: {
|
|
132
146
|
ethTokenAddress: '0xETH_TOKEN_ADDRESS', // Token on ETH (different from Pod)
|
|
133
147
|
amount: ethers.parseEther('1'),
|
|
134
148
|
to: '0x...', // Recipient
|
|
135
149
|
committeeEpoch: 0, // Hardcoded for now
|
|
136
|
-
aggregatedSignatures
|
|
150
|
+
aggregatedSignatures, // 65-byte signatures (r,s,v) concatenated
|
|
137
151
|
depositTxHash: tx.hash // Deposit TX hash from Pod
|
|
138
152
|
},
|
|
139
153
|
from: '0x...'
|
|
@@ -269,30 +283,68 @@ interface ClaimProofData {
|
|
|
269
283
|
|
|
270
284
|
### Signature Recovery Helpers
|
|
271
285
|
|
|
272
|
-
Pod
|
|
273
|
-
The
|
|
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.
|
|
274
288
|
|
|
275
289
|
```typescript
|
|
276
290
|
import {
|
|
291
|
+
extractAggregatedSignaturesWithValidators,
|
|
277
292
|
extractAggregatedSignatures,
|
|
278
|
-
|
|
279
|
-
addressFromPublicKey
|
|
293
|
+
parseDerSignature,
|
|
294
|
+
addressFromPublicKey,
|
|
295
|
+
recoverSignatureWithoutPubkey
|
|
280
296
|
} from '@tapforce/pod-bridge-sdk';
|
|
281
297
|
|
|
282
|
-
// Recommended: Extract
|
|
298
|
+
// Recommended: Extract with validator verification (correct v-values)
|
|
283
299
|
const podReceipt = await podProvider.send('eth_getTransactionReceipt', [depositTxHash]);
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
r, // r component (32 bytes hex)
|
|
289
|
-
s, // s component (32 bytes hex)
|
|
290
|
-
msgHash, // message hash that was signed
|
|
291
|
-
publicKey // signer's public key (to verify recovery)
|
|
300
|
+
const committee = await podProvider.send('pod_getCommittee', {});
|
|
301
|
+
const aggregatedSignatures = extractAggregatedSignaturesWithValidators(
|
|
302
|
+
podReceipt,
|
|
303
|
+
committee.validators // [[index, compressedPubKey], ...]
|
|
292
304
|
);
|
|
293
305
|
|
|
294
|
-
//
|
|
295
|
-
const
|
|
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);
|
|
314
|
+
|
|
315
|
+
// Utility: Derive address from uncompressed public key
|
|
316
|
+
const address = addressFromPublicKey(uncompressedPubKey);
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### Pod Receipt Format
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
interface PodTransactionReceipt {
|
|
323
|
+
// ... standard fields ...
|
|
324
|
+
attested_tx: {
|
|
325
|
+
hash: string; // Hash signed by validators
|
|
326
|
+
committee_epoch: number;
|
|
327
|
+
};
|
|
328
|
+
signatures: {
|
|
329
|
+
"0": string; // DER-encoded signature from validator 0
|
|
330
|
+
"1": string; // DER-encoded signature from validator 1
|
|
331
|
+
// ...
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
#### Committee Format
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
// pod_getCommittee response
|
|
340
|
+
{
|
|
341
|
+
validators: [
|
|
342
|
+
[0, "024ee7..."], // [index, compressed_secp256k1_pubkey]
|
|
343
|
+
[1, "025c59..."],
|
|
344
|
+
// ...
|
|
345
|
+
],
|
|
346
|
+
quorum_size: 3
|
|
347
|
+
}
|
|
296
348
|
```
|
|
297
349
|
|
|
298
350
|
## Events
|