@tapforce/pod-bridge-sdk 1.1.17 → 1.2.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 +180 -521
- package/dist/clients/action/pod-to-source-chain-client.d.ts +37 -35
- package/dist/clients/action/pod-to-source-chain-client.js +47 -49
- package/dist/clients/action/source-chain-to-pod-client.d.ts +21 -48
- package/dist/clients/action/source-chain-to-pod-client.js +23 -65
- package/dist/clients/tracker/client.d.ts +27 -9
- package/dist/clients/tracker/client.js +89 -64
- package/dist/clients/tracker/pod-tracker.service.d.ts +8 -19
- package/dist/clients/tracker/pod-tracker.service.js +20 -59
- package/dist/clients/tracker/source-chain-tracker.service.d.ts +11 -3
- package/dist/clients/tracker/source-chain-tracker.service.js +37 -32
- package/dist/index.d.ts +3 -2
- package/dist/index.js +10 -1
- package/dist/libs/abi/bridge.abi.d.ts +7 -9
- package/dist/libs/abi/bridge.abi.js +21 -41
- package/dist/libs/helpers/convert-certified-log.helper.d.ts +9 -21
- package/dist/libs/helpers/convert-certified-log.helper.js +14 -23
- package/dist/libs/helpers/signature-recovery.helper.d.ts +91 -0
- package/dist/libs/helpers/signature-recovery.helper.js +218 -0
- package/dist/libs/pod-sdk/src/provider/provider-builder.js +2 -3
- package/dist/libs/types/pod-bridge.types.d.ts +35 -19
- package/package.json +1 -1
|
@@ -11,13 +11,17 @@ 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
|
-
* -
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* - ETH -> Pod: deposits on ETH, AUTO-CLAIM on Pod (no claim needed)
|
|
15
|
+
* - Pod -> ETH: deposits on Pod, claims on ETH with aggregated validator signatures
|
|
16
|
+
* - Only ERC20 tokens supported (wrap ETH to WETH)
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
* - Deposits
|
|
20
|
-
* - Claims
|
|
18
|
+
* Source Chain (e.g., Sepolia/ETH):
|
|
19
|
+
* - Deposits lock ERC20 tokens (ETH -> Pod direction)
|
|
20
|
+
* - Claims release ERC20 tokens with validator signatures (Pod -> ETH direction)
|
|
21
|
+
*
|
|
22
|
+
* POD Chain:
|
|
23
|
+
* - Auto-claim for ETH -> Pod deposits (instant finality)
|
|
24
|
+
* - Deposits for Pod -> ETH direction
|
|
21
25
|
*/
|
|
22
26
|
class PodBridgeTrackerClient {
|
|
23
27
|
constructor(config) {
|
|
@@ -101,24 +105,34 @@ class PodBridgeTrackerClient {
|
|
|
101
105
|
.sort((a, b) => b.deposit.timestamp - a.deposit.timestamp);
|
|
102
106
|
}
|
|
103
107
|
/**
|
|
104
|
-
* Check if deposits can be claimed
|
|
108
|
+
* Check if deposits can be claimed
|
|
109
|
+
*
|
|
110
|
+
* New architecture:
|
|
111
|
+
* - ETH -> Pod: AUTO-CLAIM on Pod, no manual claim needed (always returns false)
|
|
112
|
+
* - Pod -> ETH: Manual claim needed on ETH with aggregated signatures
|
|
113
|
+
*
|
|
105
114
|
* @param deposit The bridge request to check
|
|
106
|
-
* @returns True if the deposit can be claimed
|
|
115
|
+
* @returns True if the deposit can be manually claimed (only Pod -> ETH direction)
|
|
107
116
|
*/
|
|
108
117
|
async canBeClaimed(deposit) {
|
|
109
|
-
//
|
|
118
|
+
// ETH -> Pod deposits have AUTO-CLAIM on Pod, no manual claim needed
|
|
110
119
|
if (deposit.deposit.chain === pod_bridge_types_1.BridgeChain.SOURCE_CHAIN) {
|
|
111
|
-
|
|
112
|
-
return
|
|
120
|
+
// Auto-claim on Pod - nothing to claim manually
|
|
121
|
+
return false;
|
|
113
122
|
}
|
|
114
123
|
else {
|
|
115
|
-
// POD deposits
|
|
124
|
+
// POD -> ETH deposits need manual claim on ETH
|
|
125
|
+
// POD has instant finality, so always claimable if not already claimed
|
|
116
126
|
return !deposit.isClaimed;
|
|
117
127
|
}
|
|
118
128
|
}
|
|
119
129
|
/**
|
|
120
130
|
* Batch check claim status for multiple deposits
|
|
121
|
-
*
|
|
131
|
+
*
|
|
132
|
+
* New architecture:
|
|
133
|
+
* - ETH -> Pod: AUTO-CLAIM on Pod (mark as claimed after finalization)
|
|
134
|
+
* - Pod -> ETH: Check claim events on Source Chain
|
|
135
|
+
*
|
|
122
136
|
* @private
|
|
123
137
|
*/
|
|
124
138
|
async updateClaimStatus(deposits) {
|
|
@@ -127,82 +141,93 @@ class PodBridgeTrackerClient {
|
|
|
127
141
|
}
|
|
128
142
|
console.log('[TrackerClient] Updating claim status for', deposits.length, 'deposits');
|
|
129
143
|
try {
|
|
130
|
-
// Separate deposits by their origin chain
|
|
131
|
-
const sourceChainDeposits = deposits.filter(d => d.deposit.chain === pod_bridge_types_1.BridgeChain.SOURCE_CHAIN);
|
|
132
144
|
const podDeposits = deposits.filter(d => d.deposit.chain === pod_bridge_types_1.BridgeChain.POD);
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
podDeposits.length > 0 ? this.sourceChainTracker.getClaimEvents(podDeposits) : Promise.resolve(new Map())
|
|
138
|
-
]);
|
|
139
|
-
// Combine both claim maps
|
|
140
|
-
const claimedMap = new Map([...podClaimEvents, ...sourceChainClaimEvents]);
|
|
145
|
+
// For Pod -> ETH deposits, check claim events on Source Chain
|
|
146
|
+
const sourceChainClaimEvents = podDeposits.length > 0
|
|
147
|
+
? await this.sourceChainTracker.getClaimEvents(podDeposits)
|
|
148
|
+
: new Map();
|
|
141
149
|
// Get finalized block for source chain
|
|
142
150
|
const finalizedBlock = await this.sourceChainTracker.getFinalizedBlockNumber();
|
|
143
151
|
// Update deposit status
|
|
144
|
-
for (const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
deposit
|
|
148
|
-
deposit.
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
152
|
+
for (const depositData of deposits) {
|
|
153
|
+
if (depositData.deposit.chain === pod_bridge_types_1.BridgeChain.SOURCE_CHAIN) {
|
|
154
|
+
// ETH -> Pod: AUTO-CLAIM on Pod
|
|
155
|
+
// Mark as "claimed" (auto-claimed) once the deposit is finalized
|
|
156
|
+
const isFinalized = depositData.deposit.blockNumber <= finalizedBlock;
|
|
157
|
+
depositData.isClaimed = isFinalized; // Auto-claimed after finalization
|
|
158
|
+
depositData.isClaimable = false; // No manual claim needed
|
|
159
|
+
if (isFinalized) {
|
|
160
|
+
// Auto-claim doesn't have a separate claim tx, so we mark it as such
|
|
161
|
+
depositData.claim = {
|
|
162
|
+
chain: pod_bridge_types_1.BridgeChain.POD,
|
|
163
|
+
txHash: 'auto-claim', // No separate claim TX
|
|
164
|
+
claimer: depositData.deposit.destination,
|
|
165
|
+
chainId: 1293, // Pod chain ID
|
|
166
|
+
blockNumber: 0,
|
|
167
|
+
timestamp: depositData.deposit.timestamp
|
|
168
|
+
};
|
|
169
|
+
}
|
|
162
170
|
}
|
|
163
171
|
else {
|
|
172
|
+
// Pod -> ETH: Check manual claim on Source Chain
|
|
173
|
+
const claimInfo = sourceChainClaimEvents.get(depositData.requestId);
|
|
174
|
+
if (claimInfo) {
|
|
175
|
+
depositData.isClaimed = true;
|
|
176
|
+
depositData.claim = {
|
|
177
|
+
chain: claimInfo.chain,
|
|
178
|
+
txHash: claimInfo.txHash,
|
|
179
|
+
claimer: claimInfo.claimer,
|
|
180
|
+
chainId: claimInfo.chainId,
|
|
181
|
+
blockNumber: claimInfo.blockNumber,
|
|
182
|
+
timestamp: claimInfo.timestamp
|
|
183
|
+
};
|
|
184
|
+
}
|
|
164
185
|
// POD deposits are immediately claimable (instant finality)
|
|
165
|
-
|
|
186
|
+
depositData.isClaimable = !depositData.isClaimed;
|
|
166
187
|
}
|
|
167
188
|
}
|
|
168
189
|
}
|
|
169
190
|
catch (error) {
|
|
170
191
|
console.error('[TrackerClient] Error checking claim status:', error);
|
|
171
|
-
// Fallback:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if (deposit.deposit.chain === pod_bridge_types_1.BridgeChain.SOURCE_CHAIN) {
|
|
176
|
-
deposit.isClaimable = deposit.deposit.blockNumber <= finalizedBlock && !deposit.isClaimed;
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
deposit.isClaimable = !deposit.isClaimed;
|
|
180
|
-
}
|
|
192
|
+
// Fallback: Mark Pod deposits as claimable
|
|
193
|
+
for (const deposit of deposits) {
|
|
194
|
+
if (deposit.deposit.chain === pod_bridge_types_1.BridgeChain.POD) {
|
|
195
|
+
deposit.isClaimable = !deposit.isClaimed;
|
|
181
196
|
}
|
|
182
197
|
}
|
|
183
|
-
catch (fallbackError) {
|
|
184
|
-
console.error('[TrackerClient] Error calculating isClaimable:', fallbackError);
|
|
185
|
-
}
|
|
186
198
|
}
|
|
187
199
|
}
|
|
188
200
|
/**
|
|
189
201
|
* Batch check if multiple requests have been processed on-chain
|
|
202
|
+
*
|
|
203
|
+
* New architecture:
|
|
204
|
+
* - ETH -> Pod: Auto-claimed after finalization
|
|
205
|
+
* - Pod -> ETH: Check claim events on Source Chain
|
|
206
|
+
*
|
|
190
207
|
* @param deposits Array of deposits to check
|
|
191
208
|
* @returns Array of boolean values
|
|
192
209
|
*/
|
|
193
210
|
async areRequestsProcessed(deposits) {
|
|
194
211
|
if (deposits.length === 0)
|
|
195
212
|
return [];
|
|
196
|
-
//
|
|
197
|
-
const
|
|
213
|
+
// Get finalized block for ETH -> Pod auto-claim check
|
|
214
|
+
const finalizedBlock = await this.sourceChainTracker.getFinalizedBlockNumber();
|
|
215
|
+
// Group deposits by origin chain
|
|
198
216
|
const podDeposits = deposits.filter(d => d.deposit.chain === pod_bridge_types_1.BridgeChain.POD);
|
|
199
|
-
// Check claims on
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
217
|
+
// Check claims on Source Chain for Pod -> ETH deposits
|
|
218
|
+
const sourceChainClaims = podDeposits.length > 0
|
|
219
|
+
? await this.sourceChainTracker.getClaimEvents(podDeposits)
|
|
220
|
+
: new Map();
|
|
221
|
+
return deposits.map(d => {
|
|
222
|
+
if (d.deposit.chain === pod_bridge_types_1.BridgeChain.SOURCE_CHAIN) {
|
|
223
|
+
// ETH -> Pod: Auto-claimed once finalized
|
|
224
|
+
return d.deposit.blockNumber <= finalizedBlock;
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
// Pod -> ETH: Check claim event on Source Chain
|
|
228
|
+
return sourceChainClaims.has(d.requestId);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
206
231
|
}
|
|
207
232
|
}
|
|
208
233
|
exports.PodBridgeTrackerClient = PodBridgeTrackerClient;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { BridgeRequest,
|
|
1
|
+
import { BridgeRequest, PodBridgeChainConfig } from '../../libs/types/pod-bridge.types';
|
|
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
|
+
*
|
|
5
10
|
* Responsibilities:
|
|
6
|
-
* - Fetch deposits made on POD
|
|
7
|
-
* - Fetch claims made on POD (from Source Chain deposits)
|
|
8
|
-
* - Generate certified logs for claiming on Source Chain
|
|
11
|
+
* - Fetch deposits made on POD (Pod -> ETH direction)
|
|
9
12
|
*
|
|
10
13
|
* Note: POD uses a single-block architecture where blocks are essentially
|
|
11
14
|
* timestamps. The chain has instant finality.
|
|
@@ -32,21 +35,7 @@ export declare class PodTrackerService {
|
|
|
32
35
|
/**
|
|
33
36
|
* Private method to fetch deposits from POD
|
|
34
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)
|
|
35
39
|
*/
|
|
36
40
|
private getDeposits;
|
|
37
|
-
/**
|
|
38
|
-
* Get claim events that occurred ON POD
|
|
39
|
-
* These are claims of Source Chain deposits (Source Chain → POD direction)
|
|
40
|
-
*
|
|
41
|
-
* @param deposits The Source Chain deposits to check for claims
|
|
42
|
-
* @returns Map of requestId to claim information
|
|
43
|
-
*/
|
|
44
|
-
getClaimEvents(deposits: BridgeRequest[]): Promise<Map<string, {
|
|
45
|
-
chain: BridgeChain;
|
|
46
|
-
txHash: string;
|
|
47
|
-
timestamp: number;
|
|
48
|
-
claimer: string;
|
|
49
|
-
chainId: number;
|
|
50
|
-
blockNumber: number;
|
|
51
|
-
}>>;
|
|
52
41
|
}
|
|
@@ -4,14 +4,16 @@ exports.PodTrackerService = void 0;
|
|
|
4
4
|
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
|
-
const provider_builder_1 = require("../../libs/pod-sdk/src/provider/provider-builder");
|
|
8
7
|
/**
|
|
9
8
|
* PodTrackerService - Handles tracking on the POD Chain
|
|
10
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
|
+
*
|
|
11
15
|
* Responsibilities:
|
|
12
|
-
* - Fetch deposits made on POD
|
|
13
|
-
* - Fetch claims made on POD (from Source Chain deposits)
|
|
14
|
-
* - Generate certified logs for claiming on Source Chain
|
|
16
|
+
* - Fetch deposits made on POD (Pod -> ETH direction)
|
|
15
17
|
*
|
|
16
18
|
* Note: POD uses a single-block architecture where blocks are essentially
|
|
17
19
|
* timestamps. The chain has instant finality.
|
|
@@ -20,9 +22,9 @@ class PodTrackerService {
|
|
|
20
22
|
constructor(config) {
|
|
21
23
|
this.config = config;
|
|
22
24
|
this.chainId = null;
|
|
23
|
-
this.provider =
|
|
24
|
-
this.bridge = new ethers_1.Contract(config.contractAddress, bridge_abi_1.
|
|
25
|
-
this.iface = new ethers_1.Interface(bridge_abi_1.
|
|
25
|
+
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);
|
|
26
28
|
this.initChainId();
|
|
27
29
|
}
|
|
28
30
|
async initChainId() {
|
|
@@ -44,6 +46,7 @@ class PodTrackerService {
|
|
|
44
46
|
* Note: POD has a single block, so blockNumber is essentially a timestamp
|
|
45
47
|
*/
|
|
46
48
|
async getDepositsSentBy(address) {
|
|
49
|
+
// Filter by 'from' (second indexed param): Deposit(id, from, to, token, amount)
|
|
47
50
|
return this.getDeposits({
|
|
48
51
|
depositEventFilter: [null, address, null]
|
|
49
52
|
});
|
|
@@ -53,6 +56,7 @@ class PodTrackerService {
|
|
|
53
56
|
* Note: POD has a single block, so blockNumber is essentially a timestamp
|
|
54
57
|
*/
|
|
55
58
|
async getDepositsReceivedBy(address) {
|
|
59
|
+
// Filter by 'to' (third indexed param): Deposit(id, from, to, token, amount)
|
|
56
60
|
return this.getDeposits({
|
|
57
61
|
depositEventFilter: [null, null, address]
|
|
58
62
|
});
|
|
@@ -60,23 +64,22 @@ class PodTrackerService {
|
|
|
60
64
|
/**
|
|
61
65
|
* Private method to fetch deposits from POD
|
|
62
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)
|
|
63
68
|
*/
|
|
64
69
|
async getDeposits(options) {
|
|
65
70
|
const deposits = [];
|
|
71
|
+
// Event: Deposit(bytes32 indexed id, address indexed from, address indexed to, address token, uint256 amount)
|
|
66
72
|
const depositFilter = this.bridge.filters.Deposit(...options.depositEventFilter);
|
|
67
|
-
const
|
|
68
|
-
const [depositLogs, depositNativeLogs] = await Promise.all([
|
|
69
|
-
this.bridge.queryFilter(depositFilter),
|
|
70
|
-
this.bridge.queryFilter(depositNativeFilter)
|
|
71
|
-
]);
|
|
73
|
+
const depositLogs = await this.bridge.queryFilter(depositFilter);
|
|
72
74
|
// Process deposits
|
|
73
|
-
for (const log of
|
|
75
|
+
for (const log of depositLogs) {
|
|
74
76
|
const parsed = this.iface.parseLog({
|
|
75
77
|
topics: [...log.topics],
|
|
76
78
|
data: log.data
|
|
77
79
|
});
|
|
78
80
|
if (parsed) {
|
|
79
|
-
|
|
81
|
+
// Get block for timestamp
|
|
82
|
+
const block = await this.provider.getBlock(log.blockNumber);
|
|
80
83
|
deposits.push({
|
|
81
84
|
requestId: parsed.args.id.toString(),
|
|
82
85
|
deposit: {
|
|
@@ -84,11 +87,11 @@ class PodTrackerService {
|
|
|
84
87
|
txHash: log.transactionHash,
|
|
85
88
|
depositor: parsed.args.from,
|
|
86
89
|
destination: parsed.args.to,
|
|
87
|
-
token:
|
|
90
|
+
token: parsed.args.token,
|
|
88
91
|
amount: parsed.args.amount.toString(),
|
|
89
92
|
chainId: this.chainId,
|
|
90
|
-
blockNumber:
|
|
91
|
-
timestamp: Number(
|
|
93
|
+
blockNumber: log.blockNumber, // On POD, this is essentially a timestamp
|
|
94
|
+
timestamp: block ? Number(block.timestamp) : 0
|
|
92
95
|
},
|
|
93
96
|
isClaimed: false,
|
|
94
97
|
isClaimable: false
|
|
@@ -97,47 +100,5 @@ class PodTrackerService {
|
|
|
97
100
|
}
|
|
98
101
|
return deposits;
|
|
99
102
|
}
|
|
100
|
-
/**
|
|
101
|
-
* Get claim events that occurred ON POD
|
|
102
|
-
* These are claims of Source Chain deposits (Source Chain → POD direction)
|
|
103
|
-
*
|
|
104
|
-
* @param deposits The Source Chain deposits to check for claims
|
|
105
|
-
* @returns Map of requestId to claim information
|
|
106
|
-
*/
|
|
107
|
-
async getClaimEvents(deposits) {
|
|
108
|
-
await this.ensureChainId();
|
|
109
|
-
const uniqueRecipients = [...new Set(deposits.map(d => d.deposit.destination))];
|
|
110
|
-
const allClaimLogs = [];
|
|
111
|
-
const allClaimNativeLogs = [];
|
|
112
|
-
for (const recipient of uniqueRecipients) {
|
|
113
|
-
const claimFilter = this.bridge.filters.Claim(null, null, recipient);
|
|
114
|
-
const claimNativeFilter = this.bridge.filters.ClaimNative(null, null, recipient);
|
|
115
|
-
const [claimLogs, claimNativeLogs] = await Promise.all([
|
|
116
|
-
this.bridge.queryFilter(claimFilter),
|
|
117
|
-
this.bridge.queryFilter(claimNativeFilter)
|
|
118
|
-
]);
|
|
119
|
-
allClaimLogs.push(...claimLogs);
|
|
120
|
-
allClaimNativeLogs.push(...claimNativeLogs);
|
|
121
|
-
}
|
|
122
|
-
console.log(`[POD] Found ${allClaimLogs.length} claims, ${allClaimNativeLogs.length} native claims`);
|
|
123
|
-
const claimedMap = new Map();
|
|
124
|
-
for (const log of [...allClaimLogs, ...allClaimNativeLogs]) {
|
|
125
|
-
const parsed = this.iface.parseLog({
|
|
126
|
-
topics: [...log.topics],
|
|
127
|
-
data: log.data
|
|
128
|
-
});
|
|
129
|
-
if (parsed) {
|
|
130
|
-
claimedMap.set(parsed.args.id.toString(), {
|
|
131
|
-
chain: pod_bridge_types_1.BridgeChain.POD,
|
|
132
|
-
txHash: log.transactionHash,
|
|
133
|
-
timestamp: Number(parsed.args.timestamp),
|
|
134
|
-
claimer: parsed.args.claimer,
|
|
135
|
-
chainId: this.chainId,
|
|
136
|
-
blockNumber: log.blockNumber
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
return claimedMap;
|
|
141
|
-
}
|
|
142
103
|
}
|
|
143
104
|
exports.PodTrackerService = PodTrackerService;
|
|
@@ -1,10 +1,15 @@
|
|
|
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)
|
|
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)
|
|
4
9
|
*
|
|
5
10
|
* Responsibilities:
|
|
6
|
-
* - Fetch deposits made on Source Chain
|
|
7
|
-
* - Fetch claims made on Source Chain (
|
|
11
|
+
* - Fetch deposits made on Source Chain (ETH -> Pod direction)
|
|
12
|
+
* - Fetch claims made on Source Chain (Pod -> ETH direction)
|
|
8
13
|
*/
|
|
9
14
|
export declare class SourceChainTrackerService {
|
|
10
15
|
private readonly config;
|
|
@@ -30,6 +35,9 @@ export declare class SourceChainTrackerService {
|
|
|
30
35
|
/**
|
|
31
36
|
* Get claim events that occurred ON Source Chain
|
|
32
37
|
* These are claims of POD deposits (POD → Source Chain direction)
|
|
38
|
+
* Event: Claim(bytes32 indexed id, address indexed to, address token, uint256 amount)
|
|
39
|
+
*
|
|
40
|
+
* Pod Deposit.id = ETH Claim.id - used to track if deposit was claimed
|
|
33
41
|
*
|
|
34
42
|
* @param deposits The POD deposits to check for claims
|
|
35
43
|
* @returns Map of requestId to claim information
|
|
@@ -5,19 +5,24 @@ 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)
|
|
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)
|
|
9
14
|
*
|
|
10
15
|
* Responsibilities:
|
|
11
|
-
* - Fetch deposits made on Source Chain
|
|
12
|
-
* - Fetch claims made on Source Chain (
|
|
16
|
+
* - Fetch deposits made on Source Chain (ETH -> Pod direction)
|
|
17
|
+
* - Fetch claims made on Source Chain (Pod -> ETH direction)
|
|
13
18
|
*/
|
|
14
19
|
class SourceChainTrackerService {
|
|
15
20
|
constructor(config) {
|
|
16
21
|
this.config = config;
|
|
17
22
|
this.chainId = null;
|
|
18
|
-
this.provider =
|
|
19
|
-
this.bridge = new ethers_1.Contract(config.contractAddress, bridge_abi_1.
|
|
20
|
-
this.iface = new ethers_1.Interface(bridge_abi_1.
|
|
23
|
+
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);
|
|
21
26
|
this.initChainId();
|
|
22
27
|
}
|
|
23
28
|
async initChainId() {
|
|
@@ -33,8 +38,9 @@ class SourceChainTrackerService {
|
|
|
33
38
|
* Get deposits sent by an address on Source Chain
|
|
34
39
|
*/
|
|
35
40
|
async getDepositsSentBy(address, options) {
|
|
41
|
+
// Filter by 'from' (second indexed param): Deposit(id, from, to, token, amount)
|
|
36
42
|
return this.getDeposits({
|
|
37
|
-
fromBlock: options
|
|
43
|
+
fromBlock: options?.fromBlock,
|
|
38
44
|
depositEventFilter: [null, address, null]
|
|
39
45
|
});
|
|
40
46
|
}
|
|
@@ -42,36 +48,34 @@ class SourceChainTrackerService {
|
|
|
42
48
|
* Get deposits received by an address on Source Chain
|
|
43
49
|
*/
|
|
44
50
|
async getDepositsReceivedBy(address, options) {
|
|
51
|
+
// Filter by 'to' (third indexed param): Deposit(id, from, to, token, amount)
|
|
45
52
|
return this.getDeposits({
|
|
46
|
-
fromBlock: options
|
|
53
|
+
fromBlock: options?.fromBlock,
|
|
47
54
|
depositEventFilter: [null, null, address]
|
|
48
55
|
});
|
|
49
56
|
}
|
|
50
57
|
async getDeposits(options) {
|
|
51
|
-
|
|
52
|
-
const startBlock = (_b = (_a = options === null || options === void 0 ? void 0 : options.fromBlock) !== null && _a !== void 0 ? _a : this.config.deploymentBlock) !== null && _b !== void 0 ? _b : 0;
|
|
58
|
+
const startBlock = options?.fromBlock ?? this.config.deploymentBlock ?? 0;
|
|
53
59
|
const deposits = [];
|
|
54
60
|
const currentBlock = await this.provider.getBlockNumber();
|
|
55
61
|
const BLOCK_BATCH_SIZE = 10000;
|
|
56
62
|
for (let start = startBlock; start <= currentBlock; start += BLOCK_BATCH_SIZE) {
|
|
57
63
|
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)
|
|
58
65
|
const depositFilter = this.bridge.filters.Deposit(...options.depositEventFilter);
|
|
59
|
-
const
|
|
60
|
-
const [depositLogs, depositNativeLogs] = await Promise.all([
|
|
61
|
-
this.bridge.queryFilter(depositFilter, start, end),
|
|
62
|
-
this.bridge.queryFilter(depositNativeFilter, start, end)
|
|
63
|
-
]);
|
|
66
|
+
const depositLogs = await this.bridge.queryFilter(depositFilter, start, end);
|
|
64
67
|
if (start + BLOCK_BATCH_SIZE <= currentBlock) {
|
|
65
68
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
66
69
|
}
|
|
67
70
|
// Process deposits
|
|
68
|
-
for (const log of
|
|
71
|
+
for (const log of depositLogs) {
|
|
69
72
|
const parsed = this.iface.parseLog({
|
|
70
73
|
topics: [...log.topics],
|
|
71
74
|
data: log.data
|
|
72
75
|
});
|
|
73
76
|
if (parsed) {
|
|
74
|
-
|
|
77
|
+
// Get block for timestamp
|
|
78
|
+
const block = await this.provider.getBlock(log.blockNumber);
|
|
75
79
|
deposits.push({
|
|
76
80
|
requestId: parsed.args.id.toString(),
|
|
77
81
|
deposit: {
|
|
@@ -79,11 +83,11 @@ class SourceChainTrackerService {
|
|
|
79
83
|
txHash: log.transactionHash,
|
|
80
84
|
depositor: parsed.args.from,
|
|
81
85
|
destination: parsed.args.to,
|
|
82
|
-
token:
|
|
86
|
+
token: parsed.args.token,
|
|
83
87
|
amount: parsed.args.amount.toString(),
|
|
84
88
|
chainId: this.chainId,
|
|
85
|
-
blockNumber:
|
|
86
|
-
timestamp: Number(
|
|
89
|
+
blockNumber: log.blockNumber,
|
|
90
|
+
timestamp: block ? Number(block.timestamp) : 0
|
|
87
91
|
},
|
|
88
92
|
isClaimed: false,
|
|
89
93
|
isClaimable: false
|
|
@@ -96,6 +100,9 @@ class SourceChainTrackerService {
|
|
|
96
100
|
/**
|
|
97
101
|
* Get claim events that occurred ON Source Chain
|
|
98
102
|
* These are claims of POD deposits (POD → Source Chain direction)
|
|
103
|
+
* Event: Claim(bytes32 indexed id, address indexed to, address token, uint256 amount)
|
|
104
|
+
*
|
|
105
|
+
* Pod Deposit.id = ETH Claim.id - used to track if deposit was claimed
|
|
99
106
|
*
|
|
100
107
|
* @param deposits The POD deposits to check for claims
|
|
101
108
|
* @returns Map of requestId to claim information
|
|
@@ -103,30 +110,28 @@ class SourceChainTrackerService {
|
|
|
103
110
|
async getClaimEvents(deposits) {
|
|
104
111
|
const uniqueRecipients = [...new Set(deposits.map(d => d.deposit.destination))];
|
|
105
112
|
const allClaimLogs = [];
|
|
106
|
-
const allClaimNativeLogs = [];
|
|
107
113
|
for (const recipient of uniqueRecipients) {
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
this.bridge.queryFilter(claimFilter),
|
|
112
|
-
this.bridge.queryFilter(claimNativeFilter)
|
|
113
|
-
]);
|
|
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);
|
|
114
117
|
allClaimLogs.push(...claimLogs);
|
|
115
|
-
allClaimNativeLogs.push(...claimNativeLogs);
|
|
116
118
|
}
|
|
117
|
-
console.log(`[SourceChain] Found ${allClaimLogs.length} claims
|
|
119
|
+
console.log(`[SourceChain] Found ${allClaimLogs.length} claims`);
|
|
118
120
|
const claimedMap = new Map();
|
|
119
|
-
for (const log of
|
|
121
|
+
for (const log of allClaimLogs) {
|
|
120
122
|
const parsed = this.iface.parseLog({
|
|
121
123
|
topics: [...log.topics],
|
|
122
124
|
data: log.data
|
|
123
125
|
});
|
|
124
126
|
if (parsed) {
|
|
127
|
+
// Get block for timestamp
|
|
128
|
+
const block = await this.provider.getBlock(log.blockNumber);
|
|
129
|
+
// Pod Deposit.id = ETH Claim.id
|
|
125
130
|
claimedMap.set(parsed.args.id.toString(), {
|
|
126
131
|
chain: pod_bridge_types_1.BridgeChain.SOURCE_CHAIN,
|
|
127
132
|
txHash: log.transactionHash,
|
|
128
|
-
timestamp: Number(
|
|
129
|
-
claimer: parsed.args.
|
|
133
|
+
timestamp: block ? Number(block.timestamp) : 0,
|
|
134
|
+
claimer: parsed.args.to,
|
|
130
135
|
chainId: this.chainId,
|
|
131
136
|
blockNumber: log.blockNumber
|
|
132
137
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { PodToSourceChainActionClient } from './clients/action/pod-to-source-chain-client';
|
|
2
2
|
export { SourceChainToPodActionClient } from './clients/action/source-chain-to-pod-client';
|
|
3
3
|
export { PodBridgeTrackerClient } from './clients/tracker/client';
|
|
4
|
-
export { POD_BRIDGE_ABI } from './libs/abi/bridge.abi';
|
|
5
|
-
export {
|
|
4
|
+
export { BRIDGE_ABI, POD_BRIDGE_ABI, SOURCE_CHAIN_BRIDGE_ABI, } from './libs/abi/bridge.abi';
|
|
5
|
+
export { recoverSignature65B, recoverAggregatedSignatures65B, computeDepositTxHash, extractAggregatedSignatures, extractAttestationInfo, addressFromPublicKey, } from './libs/helpers/signature-recovery.helper';
|
|
6
|
+
export { PodBridgeConfig, BridgeRequest, BridgeRequestWithType, BridgeChain, DepositType, UnsignedTransaction, ClaimProofData, 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.POD_BRIDGE_ABI = exports.PodBridgeTrackerClient = exports.SourceChainToPodActionClient = exports.PodToSourceChainActionClient = void 0;
|
|
3
|
+
exports.DepositType = exports.BridgeChain = exports.addressFromPublicKey = exports.extractAttestationInfo = 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;
|
|
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");
|
|
@@ -8,7 +8,16 @@ Object.defineProperty(exports, "SourceChainToPodActionClient", { enumerable: tru
|
|
|
8
8
|
var client_1 = require("./clients/tracker/client");
|
|
9
9
|
Object.defineProperty(exports, "PodBridgeTrackerClient", { enumerable: true, get: function () { return client_1.PodBridgeTrackerClient; } });
|
|
10
10
|
var bridge_abi_1 = require("./libs/abi/bridge.abi");
|
|
11
|
+
Object.defineProperty(exports, "BRIDGE_ABI", { enumerable: true, get: function () { return bridge_abi_1.BRIDGE_ABI; } });
|
|
11
12
|
Object.defineProperty(exports, "POD_BRIDGE_ABI", { enumerable: true, get: function () { return bridge_abi_1.POD_BRIDGE_ABI; } });
|
|
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, "extractAttestationInfo", { enumerable: true, get: function () { return signature_recovery_helper_1.extractAttestationInfo; } });
|
|
20
|
+
Object.defineProperty(exports, "addressFromPublicKey", { enumerable: true, get: function () { return signature_recovery_helper_1.addressFromPublicKey; } });
|
|
12
21
|
var pod_bridge_types_1 = require("./libs/types/pod-bridge.types");
|
|
13
22
|
Object.defineProperty(exports, "BridgeChain", { enumerable: true, get: function () { return pod_bridge_types_1.BridgeChain; } });
|
|
14
23
|
Object.defineProperty(exports, "DepositType", { enumerable: true, get: function () { return pod_bridge_types_1.DepositType; } });
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ABI for
|
|
3
|
-
*
|
|
4
|
-
* -
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* ABI for BridgeDepositWithdraw contract on Source Chain (e.g., Sepolia)
|
|
9
|
-
* - Deposits lock tokens
|
|
10
|
-
* - Claims use POD certificates with attestations and merkle proofs
|
|
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)
|
|
11
7
|
*/
|
|
8
|
+
export declare const BRIDGE_ABI: string[];
|
|
12
9
|
export declare const SOURCE_CHAIN_BRIDGE_ABI: string[];
|
|
10
|
+
export declare const POD_BRIDGE_ABI: string[];
|