@zircuit/ovault-evm 0.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 +141 -0
- package/dist/addresses.d.ts +41 -0
- package/dist/addresses.d.ts.map +1 -0
- package/dist/addresses.js +48 -0
- package/dist/contracts/EIP2612.d.ts +14 -0
- package/dist/contracts/EIP2612.d.ts.map +1 -0
- package/dist/contracts/EIP2612.js +38 -0
- package/dist/contracts/ERC20.d.ts +169 -0
- package/dist/contracts/ERC20.d.ts.map +1 -0
- package/dist/contracts/ERC20.js +222 -0
- package/dist/contracts/ERC4626.d.ts +2020 -0
- package/dist/contracts/ERC4626.d.ts.map +1 -0
- package/dist/contracts/ERC4626.js +2638 -0
- package/dist/contracts/OFT.d.ts +1736 -0
- package/dist/contracts/OFT.d.ts.map +1 -0
- package/dist/contracts/OFT.js +2251 -0
- package/dist/contracts/OVaultComposer.d.ts +94 -0
- package/dist/contracts/OVaultComposer.d.ts.map +1 -0
- package/dist/contracts/OVaultComposer.js +1629 -0
- package/dist/contracts/OVaultComposerSync.d.ts +528 -0
- package/dist/contracts/OVaultComposerSync.d.ts.map +1 -0
- package/dist/contracts/OVaultComposerSync.js +682 -0
- package/dist/contracts/OVaultComposerSyncNative.d.ts +560 -0
- package/dist/contracts/OVaultComposerSyncNative.d.ts.map +1 -0
- package/dist/contracts/OVaultComposerSyncNative.js +723 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/oVaultSync/index.d.ts +3 -0
- package/dist/oVaultSync/index.d.ts.map +1 -0
- package/dist/oVaultSync/index.js +2 -0
- package/dist/oVaultSync/tracking.d.ts +46 -0
- package/dist/oVaultSync/tracking.d.ts.map +1 -0
- package/dist/oVaultSync/tracking.js +458 -0
- package/dist/oVaultSync/transfer.d.ts +116 -0
- package/dist/oVaultSync/transfer.d.ts.map +1 -0
- package/dist/oVaultSync/transfer.js +515 -0
- package/dist/types.d.ts +202 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/package.json +51 -0
- package/src/addresses.ts +100 -0
- package/src/contracts/EIP2612.ts +38 -0
- package/src/contracts/ERC20.ts +222 -0
- package/src/contracts/ERC4626.ts +2638 -0
- package/src/contracts/OFT.ts +2251 -0
- package/src/contracts/OVaultComposer.ts +1629 -0
- package/src/contracts/OVaultComposerSync.ts +682 -0
- package/src/index.ts +3 -0
- package/src/oVaultSync/index.ts +2 -0
- package/src/oVaultSync/tracking.ts +614 -0
- package/src/oVaultSync/transfer.ts +742 -0
- package/src/types.ts +260 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/oVaultSync/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Chain } from "viem";
|
|
2
|
+
import { OVaultFailureReason, OVaultTransactionStep, OVaultWithdrawalInfo } from "../types";
|
|
3
|
+
interface TrackingChainConfigs {
|
|
4
|
+
sourceChain: Chain;
|
|
5
|
+
hubChain: Chain;
|
|
6
|
+
dstChain: Chain;
|
|
7
|
+
rpcUrls?: {
|
|
8
|
+
sourceChain?: string;
|
|
9
|
+
hubChain?: string;
|
|
10
|
+
dstChain?: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Track the OVault transaction
|
|
15
|
+
* There are 4 possible scenarios:
|
|
16
|
+
* 1. BBB - source chain, hub chain, dst chain are the same
|
|
17
|
+
* 2. BBA - source chain, hub chain are the same, dst chain is different
|
|
18
|
+
* 3. ABB - hub chain, dst chain are the same, source chain is different
|
|
19
|
+
* 4. ABA - source chain, hub chain, dst chain are different. Source chain can optionally be the same as the dst chain.
|
|
20
|
+
*
|
|
21
|
+
* @param txHash - The hash of the transaction to track on the source chain.
|
|
22
|
+
*/
|
|
23
|
+
export declare function trackOVaultSyncTransaction(txHash: `0x${string}`, viemConfigs: TrackingChainConfigs, withdrawalInfo?: OVaultWithdrawalInfo): Promise<{
|
|
24
|
+
step: OVaultTransactionStep;
|
|
25
|
+
refunded: boolean | undefined;
|
|
26
|
+
failureReason: OVaultFailureReason | undefined;
|
|
27
|
+
destinationTxHash: `0x${string}` | undefined;
|
|
28
|
+
} | {
|
|
29
|
+
step: OVaultTransactionStep;
|
|
30
|
+
failureReason: OVaultFailureReason;
|
|
31
|
+
refunded: boolean;
|
|
32
|
+
hubTxHash: `0x${string}`;
|
|
33
|
+
destinationTxHash?: undefined;
|
|
34
|
+
} | {
|
|
35
|
+
step: OVaultTransactionStep;
|
|
36
|
+
failureReason: OVaultFailureReason;
|
|
37
|
+
refunded?: undefined;
|
|
38
|
+
destinationTxHash?: undefined;
|
|
39
|
+
} | {
|
|
40
|
+
step: OVaultTransactionStep;
|
|
41
|
+
failureReason?: undefined;
|
|
42
|
+
refunded?: undefined;
|
|
43
|
+
destinationTxHash?: undefined;
|
|
44
|
+
}>;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=tracking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracking.d.ts","sourceRoot":"","sources":["../../src/oVaultSync/tracking.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EAMN,MAAM,MAAM,CAAC;AACd,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EAErB,oBAAoB,EACrB,MAAM,UAAU,CAAC;AAKlB,UAAU,oBAAoB;IAC5B,WAAW,EAAE,KAAK,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC;IAChB,QAAQ,EAAE,KAAK,CAAC;IAChB,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAijBD;;;;;;;;;GASG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,KAAK,MAAM,EAAE,EACrB,WAAW,EAAE,oBAAoB,EACjC,cAAc,CAAC,EAAE,oBAAoB;;;;;;;;;;;;;;;;;;;;;GAYtC"}
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
import { createPublicClient, decodeEventLog, http, } from "viem";
|
|
2
|
+
import { OVaultFailureReason, OVaultTransactionStep, } from "../types";
|
|
3
|
+
import { V2 as scanClient } from "@layerzerolabs/scan-client-v2";
|
|
4
|
+
import { OVaultComposerSyncAbi } from "../contracts/OVaultComposerSync";
|
|
5
|
+
import { OVaultComposerAbi } from "../contracts/OVaultComposer";
|
|
6
|
+
async function getTxStatus(txHash, client) {
|
|
7
|
+
const receipt = await client.getTransactionReceipt({ hash: txHash });
|
|
8
|
+
if (receipt.status === "reverted") {
|
|
9
|
+
return {
|
|
10
|
+
success: false,
|
|
11
|
+
error: OVaultFailureReason.UNKNOWN,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
else if (receipt.status === "success") {
|
|
15
|
+
return {
|
|
16
|
+
success: true,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
success: false,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async function isRefunded(txHash, client) {
|
|
24
|
+
const receipt = await client.waitForTransactionReceipt({
|
|
25
|
+
hash: txHash,
|
|
26
|
+
});
|
|
27
|
+
if (receipt.status !== "success") {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
for (const log of receipt.logs) {
|
|
31
|
+
try {
|
|
32
|
+
const values = decodeEventLog({
|
|
33
|
+
abi: OVaultComposerSyncAbi,
|
|
34
|
+
data: log.data,
|
|
35
|
+
topics: log.topics,
|
|
36
|
+
});
|
|
37
|
+
if (values.eventName === "Refunded") {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
// Ignore errors in decoding logs, they might not be OFT events
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
// Helper function to find the withdrawal index by looking at WithdrawalProcessed events
|
|
48
|
+
const findWithdrawalIndexInReceipt = async (message, withdrawalInfo, client) => {
|
|
49
|
+
try {
|
|
50
|
+
// Get the transaction hash from the source
|
|
51
|
+
const txHash = message?.source?.tx?.txHash;
|
|
52
|
+
if (!txHash) {
|
|
53
|
+
console.warn("No txHash found in message");
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
// Get the transaction receipt
|
|
57
|
+
const receipt = await client.getTransactionReceipt({ hash: txHash });
|
|
58
|
+
if (!receipt || receipt.logs.length === 0) {
|
|
59
|
+
console.warn("No receipt or logs found for transaction", txHash);
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const withdrawalProcessedEvents = [];
|
|
63
|
+
for (const log of receipt.logs) {
|
|
64
|
+
try {
|
|
65
|
+
const decoded = decodeEventLog({
|
|
66
|
+
abi: OVaultComposerAbi,
|
|
67
|
+
data: log.data,
|
|
68
|
+
topics: log.topics,
|
|
69
|
+
eventName: "WithdrawalProcessed",
|
|
70
|
+
});
|
|
71
|
+
const args = decoded.args;
|
|
72
|
+
withdrawalProcessedEvents.push({
|
|
73
|
+
index: args.index,
|
|
74
|
+
initiator: args.initiator,
|
|
75
|
+
timestamp: args.timestamp,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Ignore, event is not WithdrawalProcessed
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const matchIndex = withdrawalProcessedEvents.findIndex((event) => {
|
|
83
|
+
const indexMatch = event.index?.toString() === withdrawalInfo.index?.toString();
|
|
84
|
+
const initiatorMatch = event.initiator?.toLowerCase() ===
|
|
85
|
+
withdrawalInfo.initiator?.toLowerCase();
|
|
86
|
+
if (indexMatch && initiatorMatch) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
});
|
|
91
|
+
if (matchIndex < 0) {
|
|
92
|
+
console.warn("Could not find matching withdrawal in events", {
|
|
93
|
+
searchingForIndex: withdrawalInfo.index,
|
|
94
|
+
searchingForInitiator: withdrawalInfo.initiator,
|
|
95
|
+
foundInEvents: withdrawalProcessedEvents.map((e) => ({
|
|
96
|
+
index: e.index.toString(),
|
|
97
|
+
initiator: e.initiator,
|
|
98
|
+
timestamp: e.timestamp.toString(),
|
|
99
|
+
})),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return matchIndex >= 0 ? matchIndex : null;
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
console.error("Error finding withdrawal in receipt:", error);
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
async function getLzTxStatus(txHash) {
|
|
110
|
+
try {
|
|
111
|
+
const messages = await scanClient.getMessagesBySrcTxHash(txHash);
|
|
112
|
+
if (!Array.isArray(messages)) {
|
|
113
|
+
console.error("Invalid response from LayerZero scan API", {
|
|
114
|
+
txHash,
|
|
115
|
+
messages,
|
|
116
|
+
});
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
return messages;
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error("Error fetching LayerZero messages", {
|
|
123
|
+
txHash,
|
|
124
|
+
error: error instanceof Error ? error.message : error,
|
|
125
|
+
});
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async function trackBBB(txHash, viemConfigs) {
|
|
130
|
+
const { sourceChain } = viemConfigs;
|
|
131
|
+
const sourceClient = createPublicClient({
|
|
132
|
+
chain: sourceChain,
|
|
133
|
+
transport: http(viemConfigs.rpcUrls?.sourceChain),
|
|
134
|
+
});
|
|
135
|
+
const sourceTx = await getTxStatus(txHash, sourceClient);
|
|
136
|
+
// In a BBB transaction, the source chain transaction is the only transaction.
|
|
137
|
+
// If the source chain transaction fails, the transaction is refunded.
|
|
138
|
+
return {
|
|
139
|
+
step: sourceTx.success
|
|
140
|
+
? OVaultTransactionStep.COMPLETED
|
|
141
|
+
: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
142
|
+
refunded: sourceTx.error ? true : undefined,
|
|
143
|
+
failureReason: sourceTx.error,
|
|
144
|
+
destinationTxHash: sourceTx.success ? txHash : undefined,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async function trackABB(txHash, viemConfigs, withdrawalInfo) {
|
|
148
|
+
const { sourceChain, hubChain } = viemConfigs;
|
|
149
|
+
const sourceClient = createPublicClient({
|
|
150
|
+
chain: sourceChain,
|
|
151
|
+
transport: http(viemConfigs.rpcUrls?.sourceChain),
|
|
152
|
+
});
|
|
153
|
+
const hubClient = createPublicClient({
|
|
154
|
+
chain: hubChain,
|
|
155
|
+
transport: http(viemConfigs.rpcUrls?.hubChain),
|
|
156
|
+
});
|
|
157
|
+
const sourceTx = await getTxStatus(txHash, sourceClient);
|
|
158
|
+
if (sourceTx.error) {
|
|
159
|
+
return {
|
|
160
|
+
step: OVaultTransactionStep.SOURCE_CHAIN_TRANSACTION,
|
|
161
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
else if (!sourceTx.success) {
|
|
165
|
+
// Transaction is still in progress
|
|
166
|
+
return {
|
|
167
|
+
step: OVaultTransactionStep.SOURCE_CHAIN_TRANSACTION,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// Source Tx is successful, now we need to track the hub chain transaction.
|
|
171
|
+
const sourceToHubMessages = await getLzTxStatus(txHash);
|
|
172
|
+
if (sourceToHubMessages.length === 0) {
|
|
173
|
+
return {
|
|
174
|
+
step: OVaultTransactionStep.SOURCE_TO_HUB_LZ_TRANSACTION,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
let sourceToHubMessage = sourceToHubMessages[0];
|
|
178
|
+
// For withdrawals, find which message index corresponds to this specific withdrawal
|
|
179
|
+
if (withdrawalInfo) {
|
|
180
|
+
const msgIndex = await findWithdrawalIndexInReceipt(sourceToHubMessage, withdrawalInfo, sourceClient);
|
|
181
|
+
if (msgIndex === null) {
|
|
182
|
+
console.warn("Could not find withdrawal in receipt events", withdrawalInfo);
|
|
183
|
+
return {
|
|
184
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
sourceToHubMessage = sourceToHubMessages[msgIndex];
|
|
188
|
+
}
|
|
189
|
+
if (sourceToHubMessage.status.name === "INFLIGHT" ||
|
|
190
|
+
sourceToHubMessage.status.name === "CONFIRMING") {
|
|
191
|
+
// Transaction is still in progress
|
|
192
|
+
return {
|
|
193
|
+
step: OVaultTransactionStep.SOURCE_TO_HUB_LZ_TRANSACTION,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if (sourceToHubMessage.status.name !== "DELIVERED") {
|
|
197
|
+
return {
|
|
198
|
+
step: OVaultTransactionStep.SOURCE_TO_HUB_LZ_TRANSACTION,
|
|
199
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
// Track hub chain transaction
|
|
203
|
+
const executorDst = sourceToHubMessage.destination;
|
|
204
|
+
const composeTxHash = executorDst?.lzCompose?.txs?.[0]
|
|
205
|
+
?.txHash;
|
|
206
|
+
const failedCompose = executorDst?.lzCompose?.failedTx?.[0]
|
|
207
|
+
?.txHash;
|
|
208
|
+
if (failedCompose) {
|
|
209
|
+
return {
|
|
210
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
211
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
212
|
+
refunded: false,
|
|
213
|
+
hubTxHash: failedCompose,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
if (!composeTxHash) {
|
|
217
|
+
// Waiting for the compose tx to be created
|
|
218
|
+
return {
|
|
219
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const hubTx = await getTxStatus(composeTxHash, hubClient);
|
|
223
|
+
const refunded = await isRefunded(composeTxHash, hubClient);
|
|
224
|
+
return {
|
|
225
|
+
step: hubTx.success
|
|
226
|
+
? OVaultTransactionStep.COMPLETED
|
|
227
|
+
: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
228
|
+
refunded: hubTx.error || refunded ? true : undefined,
|
|
229
|
+
failureReason: hubTx.error || (refunded ? OVaultFailureReason.UNKNOWN : undefined),
|
|
230
|
+
destinationTxHash: hubTx.success ? composeTxHash : undefined,
|
|
231
|
+
hubTxHash: composeTxHash,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
async function trackBBA(txHash, viemConfigs, withdrawalInfo) {
|
|
235
|
+
const { sourceChain, dstChain } = viemConfigs;
|
|
236
|
+
const sourceClient = createPublicClient({
|
|
237
|
+
chain: sourceChain,
|
|
238
|
+
transport: http(viemConfigs.rpcUrls?.sourceChain),
|
|
239
|
+
});
|
|
240
|
+
const dstClient = createPublicClient({
|
|
241
|
+
chain: dstChain,
|
|
242
|
+
transport: http(viemConfigs.rpcUrls?.dstChain),
|
|
243
|
+
});
|
|
244
|
+
const sourceTx = await getTxStatus(txHash, sourceClient);
|
|
245
|
+
if (sourceTx.error) {
|
|
246
|
+
return {
|
|
247
|
+
step: OVaultTransactionStep.SOURCE_CHAIN_TRANSACTION,
|
|
248
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
else if (!sourceTx.success) {
|
|
252
|
+
// Transaction is still in progress
|
|
253
|
+
return {
|
|
254
|
+
step: OVaultTransactionStep.SOURCE_CHAIN_TRANSACTION,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
const hubToDstMessages = await getLzTxStatus(txHash);
|
|
258
|
+
if (hubToDstMessages.length === 0) {
|
|
259
|
+
return {
|
|
260
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
let hubToDstMessage = hubToDstMessages[0];
|
|
264
|
+
// For withdrawals, find which message index corresponds to this specific withdrawal
|
|
265
|
+
if (withdrawalInfo) {
|
|
266
|
+
const msgIndex = await findWithdrawalIndexInReceipt(hubToDstMessage, withdrawalInfo, sourceClient);
|
|
267
|
+
if (msgIndex === null) {
|
|
268
|
+
console.warn("Could not find withdrawal in receipt events", withdrawalInfo);
|
|
269
|
+
return {
|
|
270
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
hubToDstMessage = hubToDstMessages[msgIndex];
|
|
274
|
+
}
|
|
275
|
+
if (hubToDstMessage.status.name === "INFLIGHT" ||
|
|
276
|
+
hubToDstMessage.status.name === "CONFIRMING") {
|
|
277
|
+
return {
|
|
278
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
if (hubToDstMessage.status.name !== "DELIVERED") {
|
|
282
|
+
return {
|
|
283
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
284
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
// Track dst chain transaction
|
|
288
|
+
const dstTxHash = hubToDstMessage.destination?.tx?.txHash;
|
|
289
|
+
if (!dstTxHash) {
|
|
290
|
+
return {
|
|
291
|
+
step: OVaultTransactionStep.DST_CHAIN_TRANSACTION,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
const dstTx = await getTxStatus(dstTxHash, dstClient);
|
|
295
|
+
return {
|
|
296
|
+
step: dstTx.success
|
|
297
|
+
? OVaultTransactionStep.COMPLETED
|
|
298
|
+
: OVaultTransactionStep.DST_CHAIN_TRANSACTION,
|
|
299
|
+
refunded: false,
|
|
300
|
+
failureReason: dstTx.error,
|
|
301
|
+
destinationTxHash: dstTx.success ? dstTxHash : undefined,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
async function trackABA(txHash, viemConfigs, withdrawalInfo) {
|
|
305
|
+
const { sourceChain, hubChain, dstChain } = viemConfigs;
|
|
306
|
+
const sourceClient = createPublicClient({
|
|
307
|
+
chain: sourceChain,
|
|
308
|
+
transport: http(viemConfigs.rpcUrls?.sourceChain),
|
|
309
|
+
});
|
|
310
|
+
const hubClient = createPublicClient({
|
|
311
|
+
chain: hubChain,
|
|
312
|
+
transport: http(viemConfigs.rpcUrls?.hubChain),
|
|
313
|
+
});
|
|
314
|
+
const dstClient = createPublicClient({
|
|
315
|
+
chain: dstChain,
|
|
316
|
+
transport: http(viemConfigs.rpcUrls?.dstChain),
|
|
317
|
+
});
|
|
318
|
+
const sourceTx = await getTxStatus(txHash, sourceClient);
|
|
319
|
+
if (sourceTx.error) {
|
|
320
|
+
return {
|
|
321
|
+
step: OVaultTransactionStep.SOURCE_CHAIN_TRANSACTION,
|
|
322
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
else if (!sourceTx.success) {
|
|
326
|
+
// Transaction is still in progress
|
|
327
|
+
return {
|
|
328
|
+
step: OVaultTransactionStep.SOURCE_CHAIN_TRANSACTION,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
const sourceToHubMessages = await getLzTxStatus(txHash);
|
|
332
|
+
if (sourceToHubMessages.length === 0) {
|
|
333
|
+
return {
|
|
334
|
+
step: OVaultTransactionStep.SOURCE_TO_HUB_LZ_TRANSACTION,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
let sourceToHubMessage = sourceToHubMessages[0];
|
|
338
|
+
// For withdrawals, find which message index corresponds to this specific withdrawal
|
|
339
|
+
if (withdrawalInfo) {
|
|
340
|
+
const msgIndex = await findWithdrawalIndexInReceipt(sourceToHubMessage, withdrawalInfo, sourceClient);
|
|
341
|
+
if (msgIndex === null) {
|
|
342
|
+
console.warn("Could not find withdrawal in receipt events", withdrawalInfo);
|
|
343
|
+
return {
|
|
344
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
sourceToHubMessage = sourceToHubMessages[msgIndex];
|
|
348
|
+
}
|
|
349
|
+
if (sourceToHubMessage.status.name === "INFLIGHT" ||
|
|
350
|
+
sourceToHubMessage.status.name === "CONFIRMING") {
|
|
351
|
+
return {
|
|
352
|
+
step: OVaultTransactionStep.SOURCE_TO_HUB_LZ_TRANSACTION,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
if (sourceToHubMessage.status.name !== "DELIVERED") {
|
|
356
|
+
return {
|
|
357
|
+
step: OVaultTransactionStep.SOURCE_TO_HUB_LZ_TRANSACTION,
|
|
358
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
// Track hub chain transaction
|
|
362
|
+
const executorDst = sourceToHubMessage.destination;
|
|
363
|
+
const composeTxHash = executorDst?.lzCompose?.txs?.[0]
|
|
364
|
+
?.txHash;
|
|
365
|
+
if (!composeTxHash) {
|
|
366
|
+
return {
|
|
367
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
const failedCompose = executorDst?.lzCompose?.failedTx?.[0]
|
|
371
|
+
?.txHash;
|
|
372
|
+
if (executorDst?.lzCompose?.status !== "SUCCEEDED" && failedCompose) {
|
|
373
|
+
return {
|
|
374
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
375
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
376
|
+
refunded: false,
|
|
377
|
+
hubTxHash: failedCompose,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
const hubTx = await getTxStatus(composeTxHash, hubClient);
|
|
381
|
+
const refunded = await isRefunded(composeTxHash, hubClient);
|
|
382
|
+
if (hubTx.success && refunded) {
|
|
383
|
+
// Something went wrong on the hub chain, but the funds were refunded.
|
|
384
|
+
return {
|
|
385
|
+
step: OVaultTransactionStep.HUB_CHAIN_TRANSACTION,
|
|
386
|
+
refunded: true,
|
|
387
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
388
|
+
hubTxHash: composeTxHash,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
// Track hub to dst chain transaction
|
|
392
|
+
const hubToDstLzMessages = await getLzTxStatus(composeTxHash);
|
|
393
|
+
if (hubToDstLzMessages.length === 0) {
|
|
394
|
+
return {
|
|
395
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
396
|
+
hubTxHash: composeTxHash,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
const hubToDstMessage = hubToDstLzMessages[0];
|
|
400
|
+
if (hubToDstMessage.status.name === "INFLIGHT" ||
|
|
401
|
+
hubToDstMessage.status.name === "CONFIRMING") {
|
|
402
|
+
return {
|
|
403
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
404
|
+
hubTxHash: composeTxHash,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
if (hubToDstMessage.status.name !== "DELIVERED") {
|
|
408
|
+
return {
|
|
409
|
+
step: OVaultTransactionStep.HUB_TO_DST_LZ_TRANSACTION,
|
|
410
|
+
failureReason: OVaultFailureReason.UNKNOWN,
|
|
411
|
+
hubTxHash: composeTxHash,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
// Track dst chain transaction
|
|
415
|
+
const dstTxHash = hubToDstMessage.destination?.tx?.txHash;
|
|
416
|
+
if (!dstTxHash) {
|
|
417
|
+
// Waiting for the dst tx to be created
|
|
418
|
+
return {
|
|
419
|
+
step: OVaultTransactionStep.DST_CHAIN_TRANSACTION,
|
|
420
|
+
hubTxHash: composeTxHash,
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
const dstTx = await getTxStatus(dstTxHash, dstClient);
|
|
424
|
+
return {
|
|
425
|
+
step: dstTx.success
|
|
426
|
+
? OVaultTransactionStep.COMPLETED
|
|
427
|
+
: OVaultTransactionStep.DST_CHAIN_TRANSACTION,
|
|
428
|
+
refunded: false,
|
|
429
|
+
failureReason: dstTx.error,
|
|
430
|
+
destinationTxHash: dstTx.success ? dstTxHash : undefined,
|
|
431
|
+
hubTxHash: composeTxHash,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Track the OVault transaction
|
|
436
|
+
* There are 4 possible scenarios:
|
|
437
|
+
* 1. BBB - source chain, hub chain, dst chain are the same
|
|
438
|
+
* 2. BBA - source chain, hub chain are the same, dst chain is different
|
|
439
|
+
* 3. ABB - hub chain, dst chain are the same, source chain is different
|
|
440
|
+
* 4. ABA - source chain, hub chain, dst chain are different. Source chain can optionally be the same as the dst chain.
|
|
441
|
+
*
|
|
442
|
+
* @param txHash - The hash of the transaction to track on the source chain.
|
|
443
|
+
*/
|
|
444
|
+
export async function trackOVaultSyncTransaction(txHash, viemConfigs, withdrawalInfo) {
|
|
445
|
+
const { sourceChain, hubChain, dstChain } = viemConfigs;
|
|
446
|
+
if (sourceChain.id === hubChain.id && sourceChain.id === dstChain.id) {
|
|
447
|
+
return trackBBB(txHash, viemConfigs);
|
|
448
|
+
}
|
|
449
|
+
else if (sourceChain.id === hubChain.id && hubChain.id !== dstChain.id) {
|
|
450
|
+
return trackBBA(txHash, viemConfigs, withdrawalInfo);
|
|
451
|
+
}
|
|
452
|
+
else if (sourceChain.id !== hubChain.id && hubChain.id === dstChain.id) {
|
|
453
|
+
return trackABB(txHash, viemConfigs, withdrawalInfo);
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
return trackABA(txHash, viemConfigs, withdrawalInfo);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { OVaultSyncInputs, SendParams, SendParamsInput, GenerateOVaultSyncInputsProps, OVaultCoreInputs } from "../types";
|
|
2
|
+
export declare class OVaultSyncMessageBuilder {
|
|
3
|
+
private static getFormattedRefCode;
|
|
4
|
+
/**
|
|
5
|
+
* Parse a string amount to BigInt with specified decimals, always truncating (never rounding up)
|
|
6
|
+
* This is critical for LayerZero operations to avoid precision issues
|
|
7
|
+
*/
|
|
8
|
+
private static parseUnitsTruncate;
|
|
9
|
+
/**
|
|
10
|
+
* LayerZero uses 6 shared decimals for cross-chain transfers.
|
|
11
|
+
* This function removes dust below the 6 decimal precision that LayerZero won't transfer.
|
|
12
|
+
* For tokens with >6 decimals, this prevents quoteSend failures due to precision loss.
|
|
13
|
+
*/
|
|
14
|
+
private static removeLzDust;
|
|
15
|
+
static buildComposeArgument(input: SendParamsInput, messageFee: bigint): `0x${string}`;
|
|
16
|
+
/**
|
|
17
|
+
* Build the send params for the hub chain to the dst chain.
|
|
18
|
+
*
|
|
19
|
+
* @param input - The input parameters for the OVault.
|
|
20
|
+
* @returns The send params for the hub chain to the dst chain.
|
|
21
|
+
*/
|
|
22
|
+
static buildHubToDstChainSendParams(input: SendParamsInput): {
|
|
23
|
+
dstEid: number;
|
|
24
|
+
to: `0x${string}`;
|
|
25
|
+
amountLD: bigint;
|
|
26
|
+
minAmountLD: bigint;
|
|
27
|
+
extraOptions: `0x${string}`;
|
|
28
|
+
composeMsg: `0x${string}`;
|
|
29
|
+
oftCmd: `0x${string}`;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Quote the amount of shares or assets that will be received from the OVault.
|
|
33
|
+
*
|
|
34
|
+
* @param input - The input parameters for the OVault.
|
|
35
|
+
* @returns The amount of shares or assets that will be received from the OVault.
|
|
36
|
+
*/
|
|
37
|
+
static quoteOVaultOutput(input: GenerateOVaultSyncInputsProps): Promise<{
|
|
38
|
+
dstAmount: bigint;
|
|
39
|
+
minDstAmount: bigint;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Calculate the message fee for the hub chain. This is the fee that it costs to send a message from the hub chain to the dst chain.
|
|
43
|
+
*
|
|
44
|
+
* @param input - The input parameters for the OVault.
|
|
45
|
+
* @param useWalletAddress
|
|
46
|
+
* @returns The message fee for the hub chain.
|
|
47
|
+
*/
|
|
48
|
+
static calculateHubChainFee(input: SendParamsInput, useWalletAddress?: boolean): Promise<{
|
|
49
|
+
nativeFee: bigint;
|
|
50
|
+
lzTokenFee: bigint;
|
|
51
|
+
}>;
|
|
52
|
+
static getMessageFee(sendParams: SendParams, input: SendParamsInput): Promise<{
|
|
53
|
+
nativeFee: bigint;
|
|
54
|
+
lzTokenFee: bigint;
|
|
55
|
+
}>;
|
|
56
|
+
static increaseByBuffer(amount: bigint, buffer?: number): bigint;
|
|
57
|
+
static buildSendParams(input: SendParamsInput): Promise<{
|
|
58
|
+
dstEid: number;
|
|
59
|
+
to: `0x${string}`;
|
|
60
|
+
amountLD: bigint;
|
|
61
|
+
minAmountLD: bigint;
|
|
62
|
+
extraOptions: `0x${string}`;
|
|
63
|
+
composeMsg: `0x${string}`;
|
|
64
|
+
oftCmd: `0x${string}`;
|
|
65
|
+
}>;
|
|
66
|
+
static buildApproval(input: SendParamsInput): Promise<{
|
|
67
|
+
tokenAddress: `0x${string}`;
|
|
68
|
+
amount: bigint;
|
|
69
|
+
spender: `0x${string}`;
|
|
70
|
+
usePermit: boolean;
|
|
71
|
+
nonce: bigint;
|
|
72
|
+
tokenName: string;
|
|
73
|
+
tokenVersion: string;
|
|
74
|
+
needsResetApproval?: undefined;
|
|
75
|
+
} | {
|
|
76
|
+
tokenAddress: `0x${string}`;
|
|
77
|
+
amount: bigint;
|
|
78
|
+
spender: `0x${string}`;
|
|
79
|
+
usePermit: boolean;
|
|
80
|
+
needsResetApproval: boolean | undefined;
|
|
81
|
+
nonce?: undefined;
|
|
82
|
+
tokenName?: undefined;
|
|
83
|
+
tokenVersion?: undefined;
|
|
84
|
+
} | undefined>;
|
|
85
|
+
/**
|
|
86
|
+
* Resolve a {@link OVaultCoreInputs} into the full
|
|
87
|
+
* {@link GenerateOVaultSyncInputsProps} using the built-in address registry.
|
|
88
|
+
*/
|
|
89
|
+
static resolveCoreInputs(core: OVaultCoreInputs): GenerateOVaultSyncInputsProps;
|
|
90
|
+
/**
|
|
91
|
+
* Generate the inputs for the OVault.
|
|
92
|
+
*
|
|
93
|
+
* @param input - The input parameters for the OVault.
|
|
94
|
+
* @returns Inputs to call contracts to perform Deposit or Redeem on the OVault.
|
|
95
|
+
*/
|
|
96
|
+
static generateOVaultInputs(input: OVaultCoreInputs): Promise<OVaultSyncInputs>;
|
|
97
|
+
/**
|
|
98
|
+
* Encode to avoid ABI-union incompatibility that arises when passing the
|
|
99
|
+
* discriminated-union `OVaultSyncInputs` directly to viem's `writeContract`.
|
|
100
|
+
*
|
|
101
|
+
* @param inputs - The output from `generateOVaultInputs`.
|
|
102
|
+
* @param permitArgs - Optional permit arguments (`[deadline, v, r, s]`) to
|
|
103
|
+
* append when using the EIP-2612 permit flow.
|
|
104
|
+
*/
|
|
105
|
+
static encodeTransactionRequest(inputs: OVaultSyncInputs, permitArgs?: readonly [
|
|
106
|
+
bigint,
|
|
107
|
+
number | bigint,
|
|
108
|
+
`0x${string}`,
|
|
109
|
+
`0x${string}`
|
|
110
|
+
]): {
|
|
111
|
+
to: `0x${string}`;
|
|
112
|
+
data: `0x${string}`;
|
|
113
|
+
value: bigint;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=transfer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transfer.d.ts","sourceRoot":"","sources":["../../src/oVaultSync/transfer.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,6BAA6B,EAE7B,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAKlB,qBAAa,wBAAwB;IACnC,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAMlC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAUjC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;IAM3B,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM;IA2BtE;;;;;OAKG;IACH,MAAM,CAAC,4BAA4B,CAAC,KAAK,EAAE,eAAe;;;;;sBAoBrB,KAAK,MAAM,EAAE;oBAC1B,KAAK,MAAM,EAAE;;;IAOrC;;;;;OAKG;WACU,iBAAiB,CAC5B,KAAK,EAAE,6BAA6B,GACnC,OAAO,CAAC;QACT,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IAuDF;;;;;;OAMG;WACU,oBAAoB,CAC/B,KAAK,EAAE,eAAe,EACtB,gBAAgB,UAAO;;;;WA0EZ,aAAa,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,eAAe;;;;IAyCzE,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,MAAU;WAW7C,eAAe,CAAC,KAAK,EAAE,eAAe;;;;;sBAjNd,KAAK,MAAM,EAAE;oBAC1B,KAAK,MAAM,EAAE;;;WA8PxB,aAAa,CAAC,KAAK,EAAE,eAAe;;;;;eA6GZ,MAAM;mBACE,MAAM;;;;;;;;;;;;;IA0BnD;;;OAGG;IACH,MAAM,CAAC,iBAAiB,CACtB,IAAI,EAAE,gBAAgB,GACrB,6BAA6B;IAmFhC;;;;;OAKG;WACU,oBAAoB,CAC/B,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,gBAAgB,CAAC;IAyG5B;;;;;;;OAOG;IACH,MAAM,CAAC,wBAAwB,CAC7B,MAAM,EAAE,gBAAgB,EACxB,UAAU,CAAC,EAAE,SAAS;QACpB,MAAM;QACN,MAAM,GAAG,MAAM;QACf,KAAK,MAAM,EAAE;QACb,KAAK,MAAM,EAAE;KACd,GACA;QAAE,EAAE,EAAE,KAAK,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;CAoB7D"}
|