@forevermoney/sdk 0.1.0 → 0.2.0
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/CHANGELOG.md +21 -0
- package/README.md +27 -5
- package/dist/index.cjs +350 -223
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +49 -27
- package/dist/index.d.ts +49 -27
- package/dist/index.js +356 -206
- package/dist/index.js.map +1 -1
- package/examples/viem.ts +64 -0
- package/package.json +5 -6
package/dist/index.cjs
CHANGED
|
@@ -69,14 +69,14 @@ __export(index_exports, {
|
|
|
69
69
|
ss58ToPublicKey: () => ss58ToPublicKey,
|
|
70
70
|
toEip1193Transaction: () => toEip1193Transaction,
|
|
71
71
|
toEthersTransaction: () => toEthersTransaction,
|
|
72
|
+
toViemTransaction: () => toViemTransaction,
|
|
72
73
|
vaultManagerFromCreationReceipt: () => vaultManagerFromCreationReceipt
|
|
73
74
|
});
|
|
74
75
|
module.exports = __toCommonJS(index_exports);
|
|
75
76
|
|
|
76
77
|
// src/core/addresses.ts
|
|
77
|
-
var
|
|
78
|
-
var
|
|
79
|
-
var import_ethers = require("ethers");
|
|
78
|
+
var import_substrate_bindings = require("@polkadot-api/substrate-bindings");
|
|
79
|
+
var import_viem = require("viem");
|
|
80
80
|
|
|
81
81
|
// src/core/errors.ts
|
|
82
82
|
var ForeverMoneyError = class extends Error {
|
|
@@ -93,22 +93,33 @@ var ForeverMoneyError = class extends Error {
|
|
|
93
93
|
// src/core/addresses.ts
|
|
94
94
|
var BITTENSOR_SS58_PREFIX = 42;
|
|
95
95
|
function normalizeEvmAddress(value) {
|
|
96
|
-
|
|
96
|
+
const candidate = typeof value === "string" && /^0x[0-9A-F]{40}$/.test(value) ? value.toLowerCase() : value;
|
|
97
|
+
if (!(0, import_viem.isAddress)(candidate) || candidate === import_viem.zeroAddress) {
|
|
97
98
|
throw new ForeverMoneyError(
|
|
98
99
|
"INVALID_ADDRESS",
|
|
99
100
|
"Expected a non-zero EVM address."
|
|
100
101
|
);
|
|
101
102
|
}
|
|
102
|
-
return (0,
|
|
103
|
+
return (0, import_viem.getAddress)(candidate);
|
|
103
104
|
}
|
|
104
105
|
function evmToMirrorSS58(evmAddress) {
|
|
105
|
-
return (0,
|
|
106
|
+
return (0, import_substrate_bindings.AccountId)(BITTENSOR_SS58_PREFIX).dec(
|
|
107
|
+
(0, import_substrate_bindings.Blake2256)(
|
|
108
|
+
(0, import_viem.concat)([
|
|
109
|
+
(0, import_viem.stringToBytes)("evm:"),
|
|
110
|
+
(0, import_viem.hexToBytes)(normalizeEvmAddress(evmAddress))
|
|
111
|
+
])
|
|
112
|
+
)
|
|
113
|
+
);
|
|
106
114
|
}
|
|
107
115
|
function decodeBittensorAddress(value) {
|
|
108
116
|
try {
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
|
|
117
|
+
if (typeof value !== "string" || !value || value.startsWith("0x"))
|
|
118
|
+
throw new Error("Raw hex is not SS58.");
|
|
119
|
+
const info = (0, import_substrate_bindings.getSs58AddressInfo)(value);
|
|
120
|
+
if (!info.isValid || info.ss58Format !== BITTENSOR_SS58_PREFIX || info.publicKey.length !== 32)
|
|
121
|
+
throw new Error("Invalid Bittensor address.");
|
|
122
|
+
const publicKey = info.publicKey;
|
|
112
123
|
return publicKey;
|
|
113
124
|
} catch {
|
|
114
125
|
throw new ForeverMoneyError(
|
|
@@ -118,7 +129,7 @@ function decodeBittensorAddress(value) {
|
|
|
118
129
|
}
|
|
119
130
|
}
|
|
120
131
|
function normalizeSS58(value) {
|
|
121
|
-
return (0,
|
|
132
|
+
return (0, import_substrate_bindings.AccountId)(BITTENSOR_SS58_PREFIX).dec(decodeBittensorAddress(value));
|
|
122
133
|
}
|
|
123
134
|
function isBittensorSS58(value) {
|
|
124
135
|
try {
|
|
@@ -129,14 +140,14 @@ function isBittensorSS58(value) {
|
|
|
129
140
|
}
|
|
130
141
|
}
|
|
131
142
|
function ss58ToPublicKey(value) {
|
|
132
|
-
return (0,
|
|
143
|
+
return (0, import_viem.bytesToHex)(decodeBittensorAddress(value));
|
|
133
144
|
}
|
|
134
145
|
|
|
135
146
|
// src/core/amounts.ts
|
|
136
|
-
var
|
|
147
|
+
var import_viem3 = require("viem");
|
|
137
148
|
|
|
138
149
|
// src/chains/deployment.ts
|
|
139
|
-
var
|
|
150
|
+
var import_viem2 = require("viem");
|
|
140
151
|
var BASE_CHAIN_ID = 8453;
|
|
141
152
|
var ROBINHOOD_CHAIN_ID = 4663;
|
|
142
153
|
var SUBTENSOR_CHAIN_ID = 964;
|
|
@@ -154,26 +165,26 @@ var foreverMoneyDeployment = Object.freeze({
|
|
|
154
165
|
chainId: BASE_CHAIN_ID,
|
|
155
166
|
ccipSelector: BASE_CCIP_SELECTOR,
|
|
156
167
|
contracts: Object.freeze({
|
|
157
|
-
gateway: (0,
|
|
158
|
-
wrappedTao: (0,
|
|
168
|
+
gateway: (0, import_viem2.getAddress)("0x5EF3d7D19e4b233a1A169DA0d5CB02ec6b160a2C"),
|
|
169
|
+
wrappedTao: (0, import_viem2.getAddress)(
|
|
159
170
|
"0xf3081494b87e8d5fb7960f066e931d1d0e6e3d67"
|
|
160
171
|
),
|
|
161
|
-
ccipRouter: (0,
|
|
172
|
+
ccipRouter: (0, import_viem2.getAddress)(
|
|
162
173
|
"0x881e3A65B4d4a04dD529061dd0071cf975F58bCD"
|
|
163
174
|
),
|
|
164
|
-
ccipOffRampFromSubtensor: (0,
|
|
175
|
+
ccipOffRampFromSubtensor: (0, import_viem2.getAddress)(
|
|
165
176
|
"0xf09AFe78d3c7d359b334d7cB88995751F7eC5E13"
|
|
166
177
|
),
|
|
167
|
-
vaultFactory: (0,
|
|
178
|
+
vaultFactory: (0, import_viem2.getAddress)(
|
|
168
179
|
"0x9b7F3c7aa335D8BF9f91741E541820466735F868"
|
|
169
180
|
),
|
|
170
|
-
vaultManagerImplementation: (0,
|
|
181
|
+
vaultManagerImplementation: (0, import_viem2.getAddress)(
|
|
171
182
|
"0x235Ad8654fe3a1619a9892eBCaD9361F416168da"
|
|
172
183
|
),
|
|
173
|
-
batchLiquidityManagerQuery: (0,
|
|
184
|
+
batchLiquidityManagerQuery: (0, import_viem2.getAddress)(
|
|
174
185
|
"0xd117176C5E6809b68500995F59589A8c081565A5"
|
|
175
186
|
),
|
|
176
|
-
weth: (0,
|
|
187
|
+
weth: (0, import_viem2.getAddress)("0x4200000000000000000000000000000000000006")
|
|
177
188
|
}),
|
|
178
189
|
deploymentBlock: 50098800
|
|
179
190
|
}),
|
|
@@ -183,14 +194,14 @@ var foreverMoneyDeployment = Object.freeze({
|
|
|
183
194
|
chainId: ROBINHOOD_CHAIN_ID,
|
|
184
195
|
ccipSelector: ROBINHOOD_CCIP_SELECTOR,
|
|
185
196
|
contracts: Object.freeze({
|
|
186
|
-
gateway: (0,
|
|
187
|
-
wrappedTao: (0,
|
|
197
|
+
gateway: (0, import_viem2.getAddress)("0x53Dcc4FE04193e489BE537F722F65317DB1E65d8"),
|
|
198
|
+
wrappedTao: (0, import_viem2.getAddress)(
|
|
188
199
|
"0xf3081494B87e8D5fb7960f066E931D1D0e6E3d67"
|
|
189
200
|
),
|
|
190
|
-
ccipRouter: (0,
|
|
201
|
+
ccipRouter: (0, import_viem2.getAddress)(
|
|
191
202
|
"0x06fC836cf9839B1cd891C440A0a45242DA6Ae1c9"
|
|
192
203
|
),
|
|
193
|
-
ccipOffRampFromSubtensor: (0,
|
|
204
|
+
ccipOffRampFromSubtensor: (0, import_viem2.getAddress)(
|
|
194
205
|
"0xcDca5D374e46A6DDDab50bD2D9acB8c796eC35C3"
|
|
195
206
|
)
|
|
196
207
|
})
|
|
@@ -199,23 +210,23 @@ var foreverMoneyDeployment = Object.freeze({
|
|
|
199
210
|
chainId: SUBTENSOR_CHAIN_ID,
|
|
200
211
|
ccipSelector: SUBTENSOR_CCIP_SELECTOR,
|
|
201
212
|
contracts: Object.freeze({
|
|
202
|
-
gateway: (0,
|
|
203
|
-
alphaVault: (0,
|
|
213
|
+
gateway: (0, import_viem2.getAddress)("0x998f20Fea90bF7792774dECc7f994716442B1705"),
|
|
214
|
+
alphaVault: (0, import_viem2.getAddress)(
|
|
204
215
|
"0x11837459896D96F821a8D88eC93a3C8D152033D4"
|
|
205
216
|
),
|
|
206
|
-
wrappedTao: (0,
|
|
217
|
+
wrappedTao: (0, import_viem2.getAddress)(
|
|
207
218
|
"0xC5b6C1632d34901239396F5E1BDe54B342900256"
|
|
208
219
|
),
|
|
209
|
-
ccipRouter: (0,
|
|
220
|
+
ccipRouter: (0, import_viem2.getAddress)(
|
|
210
221
|
"0xD941fBEcD2b971d0F54b4C34286C95faB52B60B8"
|
|
211
222
|
),
|
|
212
|
-
ccipOffRampFromBase: (0,
|
|
223
|
+
ccipOffRampFromBase: (0, import_viem2.getAddress)(
|
|
213
224
|
"0x51a6150400ed9F0Ae240F5D1b15E3b45Fc4339C7"
|
|
214
225
|
),
|
|
215
|
-
ccipOffRampFromRobinhood: (0,
|
|
226
|
+
ccipOffRampFromRobinhood: (0, import_viem2.getAddress)(
|
|
216
227
|
"0x51a6150400ed9F0Ae240F5D1b15E3b45Fc4339C7"
|
|
217
228
|
),
|
|
218
|
-
stakingPrecompile: (0,
|
|
229
|
+
stakingPrecompile: (0, import_viem2.getAddress)(
|
|
219
230
|
"0x0000000000000000000000000000000000000805"
|
|
220
231
|
)
|
|
221
232
|
})
|
|
@@ -245,7 +256,7 @@ function parseTaoAmount(value) {
|
|
|
245
256
|
}
|
|
246
257
|
let amount;
|
|
247
258
|
try {
|
|
248
|
-
amount = (0,
|
|
259
|
+
amount = (0, import_viem3.parseUnits)(value, 18);
|
|
249
260
|
} catch {
|
|
250
261
|
throw new ForeverMoneyError(
|
|
251
262
|
"AMOUNT_NOT_WHOLE_RAO",
|
|
@@ -274,7 +285,7 @@ function assertWholeRao(amountWei) {
|
|
|
274
285
|
"The amount cannot be negative."
|
|
275
286
|
);
|
|
276
287
|
}
|
|
277
|
-
if (amountWei >
|
|
288
|
+
if (amountWei > import_viem3.maxUint256) {
|
|
278
289
|
throw new ForeverMoneyError(
|
|
279
290
|
"INVALID_TRANSACTION_PLAN",
|
|
280
291
|
"The amount exceeds uint256."
|
|
@@ -300,7 +311,7 @@ function formatTaoAmount(amountWei) {
|
|
|
300
311
|
"A TAO amount cannot be negative."
|
|
301
312
|
);
|
|
302
313
|
}
|
|
303
|
-
if (amountWei >
|
|
314
|
+
if (amountWei > import_viem3.maxUint256) {
|
|
304
315
|
throw new ForeverMoneyError(
|
|
305
316
|
"INVALID_TRANSACTION_PLAN",
|
|
306
317
|
"The TAO amount exceeds uint256."
|
|
@@ -312,7 +323,8 @@ function formatTaoAmount(amountWei) {
|
|
|
312
323
|
"TAO amounts must resolve to a whole RAO."
|
|
313
324
|
);
|
|
314
325
|
}
|
|
315
|
-
|
|
326
|
+
const formatted = (0, import_viem3.formatUnits)(amountWei, 18);
|
|
327
|
+
return formatted.includes(".") ? formatted : `${formatted}.0`;
|
|
316
328
|
}
|
|
317
329
|
function mulDivCeil(value, numerator, denominator) {
|
|
318
330
|
return (value * numerator + denominator - 1n) / denominator;
|
|
@@ -335,7 +347,7 @@ function feeWithBuffer(fee) {
|
|
|
335
347
|
BASIS_POINTS + NETWORK_FEE_BUFFER_BPS,
|
|
336
348
|
BASIS_POINTS
|
|
337
349
|
);
|
|
338
|
-
if (buffered >
|
|
350
|
+
if (buffered > import_viem3.maxUint256) {
|
|
339
351
|
throw new ForeverMoneyError(
|
|
340
352
|
"INVALID_TRANSACTION_PLAN",
|
|
341
353
|
"The buffered network fee exceeds uint256."
|
|
@@ -361,7 +373,7 @@ function gasLimitWithBuffer(gasLimit) {
|
|
|
361
373
|
BASIS_POINTS + GAS_LIMIT_BUFFER_BPS,
|
|
362
374
|
BASIS_POINTS
|
|
363
375
|
);
|
|
364
|
-
if (buffered >
|
|
376
|
+
if (buffered > import_viem3.maxUint256) {
|
|
365
377
|
throw new ForeverMoneyError(
|
|
366
378
|
"INVALID_TRANSACTION_PLAN",
|
|
367
379
|
"The buffered gas limit exceeds uint256."
|
|
@@ -445,10 +457,10 @@ var foreverMoneyAbis = Object.freeze({
|
|
|
445
457
|
});
|
|
446
458
|
|
|
447
459
|
// src/bridge/plans.ts
|
|
448
|
-
var
|
|
460
|
+
var import_viem6 = require("viem");
|
|
449
461
|
|
|
450
462
|
// src/core/plans.ts
|
|
451
|
-
var
|
|
463
|
+
var import_viem4 = require("viem");
|
|
452
464
|
function createTransactionPlan(plan) {
|
|
453
465
|
const steps = plan.steps.map(
|
|
454
466
|
(step2) => Object.freeze({
|
|
@@ -465,12 +477,12 @@ function createTransactionPlan(plan) {
|
|
|
465
477
|
};
|
|
466
478
|
return Object.freeze({
|
|
467
479
|
...versionedPlan,
|
|
468
|
-
hash: (0,
|
|
480
|
+
hash: (0, import_viem4.keccak256)((0, import_viem4.stringToBytes)(JSON.stringify(versionedPlan)))
|
|
469
481
|
});
|
|
470
482
|
}
|
|
471
483
|
|
|
472
484
|
// src/core/validation.ts
|
|
473
|
-
var
|
|
485
|
+
var import_viem5 = require("viem");
|
|
474
486
|
function assertBigInt(amount, label) {
|
|
475
487
|
if (typeof amount !== "bigint") {
|
|
476
488
|
throw new ForeverMoneyError(
|
|
@@ -493,7 +505,7 @@ function assertPositiveAmount(amount, label) {
|
|
|
493
505
|
`${label} cannot be negative.`
|
|
494
506
|
);
|
|
495
507
|
}
|
|
496
|
-
if (amount >
|
|
508
|
+
if (amount > import_viem5.maxUint256) {
|
|
497
509
|
throw new ForeverMoneyError(
|
|
498
510
|
"INVALID_TRANSACTION_PLAN",
|
|
499
511
|
`${label} exceeds uint256.`
|
|
@@ -508,7 +520,7 @@ function assertNonNegativeAmount(amount, label) {
|
|
|
508
520
|
`${label} cannot be negative.`
|
|
509
521
|
);
|
|
510
522
|
}
|
|
511
|
-
if (amount >
|
|
523
|
+
if (amount > import_viem5.maxUint256) {
|
|
512
524
|
throw new ForeverMoneyError(
|
|
513
525
|
"INVALID_TRANSACTION_PLAN",
|
|
514
526
|
`${label} exceeds uint256.`
|
|
@@ -540,7 +552,7 @@ function assertRecord(value, label) {
|
|
|
540
552
|
}
|
|
541
553
|
}
|
|
542
554
|
function normalizeBytes32(value, label) {
|
|
543
|
-
if (!(0,
|
|
555
|
+
if (!(0, import_viem5.isHex)(value, { strict: true }) || value.length !== 66) {
|
|
544
556
|
throw new ForeverMoneyError(
|
|
545
557
|
"INVALID_BYTES32",
|
|
546
558
|
`${label} must be a 32-byte hex value.`
|
|
@@ -549,14 +561,14 @@ function normalizeBytes32(value, label) {
|
|
|
549
561
|
return value.toLowerCase();
|
|
550
562
|
}
|
|
551
563
|
function normalizeOptionalBytes32(value, label) {
|
|
552
|
-
return value === void 0 ?
|
|
564
|
+
return value === void 0 ? import_viem5.zeroHash : normalizeBytes32(value, label);
|
|
553
565
|
}
|
|
554
566
|
|
|
555
567
|
// src/bridge/plans.ts
|
|
556
|
-
var
|
|
557
|
-
var
|
|
558
|
-
var
|
|
559
|
-
var
|
|
568
|
+
var erc20Abi = (0, import_viem6.parseAbi)(ERC20_ABI);
|
|
569
|
+
var spokeAbi = (0, import_viem6.parseAbi)(SPOKE_GATEWAY_ABI);
|
|
570
|
+
var alphaAbi = (0, import_viem6.parseAbi)(ALPHA_GATEWAY_ABI);
|
|
571
|
+
var stakingAbi = (0, import_viem6.parseAbi)(STAKING_ABI);
|
|
560
572
|
var MIN_LIQUID_EVM_TO_SUBTENSOR_WEI = 10000000000000000n;
|
|
561
573
|
var MIN_LIQUID_BASE_TO_SUBTENSOR_WEI = MIN_LIQUID_EVM_TO_SUBTENSOR_WEI;
|
|
562
574
|
function assertDelivery(value) {
|
|
@@ -625,10 +637,11 @@ function buildEvmToSubtensorPlan(input) {
|
|
|
625
637
|
evm.chainId,
|
|
626
638
|
sender,
|
|
627
639
|
evm.contracts.wrappedTao,
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
640
|
+
(0, import_viem6.encodeFunctionData)({
|
|
641
|
+
abi: erc20Abi,
|
|
642
|
+
functionName: "approve",
|
|
643
|
+
args: [evm.contracts.gateway, input.amountWei]
|
|
644
|
+
}),
|
|
632
645
|
0n
|
|
633
646
|
)
|
|
634
647
|
);
|
|
@@ -641,10 +654,11 @@ function buildEvmToSubtensorPlan(input) {
|
|
|
641
654
|
evm.chainId,
|
|
642
655
|
sender,
|
|
643
656
|
evm.contracts.gateway,
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
657
|
+
(0, import_viem6.encodeFunctionData)({
|
|
658
|
+
abi: spokeAbi,
|
|
659
|
+
functionName: "bridgeToFinney",
|
|
660
|
+
args: [evm.contracts.wrappedTao, input.amountWei, exit]
|
|
661
|
+
}),
|
|
648
662
|
value,
|
|
649
663
|
input.estimatedBridgeGas === void 0 ? void 0 : gasLimitWithBuffer(input.estimatedBridgeGas)
|
|
650
664
|
)
|
|
@@ -691,11 +705,15 @@ function buildSubtensorToEvmPlan(input) {
|
|
|
691
705
|
subtensor.chainId,
|
|
692
706
|
sender,
|
|
693
707
|
subtensor.contracts.stakingPrecompile,
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
708
|
+
(0, import_viem6.encodeFunctionData)({
|
|
709
|
+
abi: stakingAbi,
|
|
710
|
+
functionName: "approve",
|
|
711
|
+
args: [
|
|
712
|
+
subtensor.contracts.gateway,
|
|
713
|
+
input.netuid,
|
|
714
|
+
amountRao
|
|
715
|
+
]
|
|
716
|
+
}),
|
|
699
717
|
0n
|
|
700
718
|
)
|
|
701
719
|
);
|
|
@@ -717,14 +735,18 @@ function buildSubtensorToEvmPlan(input) {
|
|
|
717
735
|
subtensor.chainId,
|
|
718
736
|
sender,
|
|
719
737
|
subtensor.contracts.gateway,
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
738
|
+
(0, import_viem6.encodeFunctionData)({
|
|
739
|
+
abi: alphaAbi,
|
|
740
|
+
functionName: "bridgeOut",
|
|
741
|
+
args: [
|
|
742
|
+
evm.ccipSelector,
|
|
743
|
+
subtensor.contracts.wrappedTao,
|
|
744
|
+
recipient,
|
|
745
|
+
taoAmount,
|
|
746
|
+
stakedAlphaRao,
|
|
747
|
+
input.amountWei
|
|
748
|
+
]
|
|
749
|
+
}),
|
|
728
750
|
value,
|
|
729
751
|
input.estimatedBridgeGas === void 0 ? void 0 : gasLimitWithBuffer(input.estimatedBridgeGas)
|
|
730
752
|
)
|
|
@@ -750,29 +772,29 @@ async function prepareEvmToSubtensor(provider, input) {
|
|
|
750
772
|
wantLiquid: input.delivery === "liquid",
|
|
751
773
|
minTaoOut: input.amountWei
|
|
752
774
|
};
|
|
753
|
-
const token = new import_ethers6.Contract(evm.contracts.wrappedTao, ERC20_ABI, provider);
|
|
754
|
-
const gateway = new import_ethers6.Contract(
|
|
755
|
-
evm.contracts.gateway,
|
|
756
|
-
SPOKE_GATEWAY_ABI,
|
|
757
|
-
provider
|
|
758
|
-
);
|
|
759
775
|
const [allowanceWei, exactNetworkFeeWei] = await Promise.all([
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
776
|
+
provider.readContract({
|
|
777
|
+
address: evm.contracts.wrappedTao,
|
|
778
|
+
abi: erc20Abi,
|
|
779
|
+
functionName: "allowance",
|
|
780
|
+
args: [sender, evm.contracts.gateway]
|
|
781
|
+
}),
|
|
782
|
+
provider.readContract({
|
|
783
|
+
address: evm.contracts.gateway,
|
|
784
|
+
abi: spokeAbi,
|
|
785
|
+
functionName: "quoteBridgeToFinney",
|
|
786
|
+
args: [evm.contracts.wrappedTao, input.amountWei, exit]
|
|
787
|
+
})
|
|
767
788
|
]);
|
|
768
789
|
let estimatedBridgeGas;
|
|
769
790
|
if (allowanceWei >= input.amountWei) {
|
|
770
|
-
const data =
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
791
|
+
const data = (0, import_viem6.encodeFunctionData)({
|
|
792
|
+
abi: spokeAbi,
|
|
793
|
+
functionName: "bridgeToFinney",
|
|
794
|
+
args: [evm.contracts.wrappedTao, input.amountWei, exit]
|
|
795
|
+
});
|
|
774
796
|
estimatedBridgeGas = await provider.estimateGas({
|
|
775
|
-
|
|
797
|
+
account: sender,
|
|
776
798
|
to: evm.contracts.gateway,
|
|
777
799
|
data,
|
|
778
800
|
value: feeWithBuffer(exactNetworkFeeWei)
|
|
@@ -800,17 +822,17 @@ async function prepareSubtensorToEvm(provider, input) {
|
|
|
800
822
|
assertWholeRao(input.amountWei);
|
|
801
823
|
const { subtensor } = foreverMoneyDeployment;
|
|
802
824
|
const evm = getForeverMoneyEvmDeployment(input.evmChain);
|
|
803
|
-
const
|
|
804
|
-
subtensor.contracts.gateway,
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
);
|
|
825
|
+
const exactNetworkFeeWei = await provider.readContract({
|
|
826
|
+
address: subtensor.contracts.gateway,
|
|
827
|
+
abi: alphaAbi,
|
|
828
|
+
functionName: "quoteBridgeOut",
|
|
829
|
+
args: [
|
|
830
|
+
evm.ccipSelector,
|
|
831
|
+
subtensor.contracts.wrappedTao,
|
|
832
|
+
recipient,
|
|
833
|
+
input.amountWei
|
|
834
|
+
]
|
|
835
|
+
});
|
|
814
836
|
let stakingAllowanceRao;
|
|
815
837
|
if (input.source === "staked") {
|
|
816
838
|
if (input.netuid === void 0) {
|
|
@@ -820,16 +842,12 @@ async function prepareSubtensorToEvm(provider, input) {
|
|
|
820
842
|
);
|
|
821
843
|
}
|
|
822
844
|
assertNonNegativeAmount(input.netuid, "netuid");
|
|
823
|
-
|
|
824
|
-
subtensor.contracts.stakingPrecompile,
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
sender,
|
|
830
|
-
subtensor.contracts.gateway,
|
|
831
|
-
input.netuid
|
|
832
|
-
);
|
|
845
|
+
stakingAllowanceRao = await provider.readContract({
|
|
846
|
+
address: subtensor.contracts.stakingPrecompile,
|
|
847
|
+
abi: stakingAbi,
|
|
848
|
+
functionName: "allowance",
|
|
849
|
+
args: [sender, subtensor.contracts.gateway, input.netuid]
|
|
850
|
+
});
|
|
833
851
|
}
|
|
834
852
|
const taoAmount = input.source === "liquid" ? input.amountWei : 0n;
|
|
835
853
|
const stakedAlphaRao = input.source === "staked" ? input.amountWei / EVM_WEI_PER_RAO : 0n;
|
|
@@ -838,16 +856,20 @@ async function prepareSubtensorToEvm(provider, input) {
|
|
|
838
856
|
let estimatedBridgeGas;
|
|
839
857
|
if (input.source === "liquid" || stakingAllowanceRao !== void 0 && stakingAllowanceRao >= stakedAlphaRao) {
|
|
840
858
|
estimatedBridgeGas = await provider.estimateGas({
|
|
841
|
-
|
|
859
|
+
account: sender,
|
|
842
860
|
to: subtensor.contracts.gateway,
|
|
843
|
-
data:
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
861
|
+
data: (0, import_viem6.encodeFunctionData)({
|
|
862
|
+
abi: alphaAbi,
|
|
863
|
+
functionName: "bridgeOut",
|
|
864
|
+
args: [
|
|
865
|
+
evm.ccipSelector,
|
|
866
|
+
subtensor.contracts.wrappedTao,
|
|
867
|
+
recipient,
|
|
868
|
+
taoAmount,
|
|
869
|
+
stakedAlphaRao,
|
|
870
|
+
input.amountWei
|
|
871
|
+
]
|
|
872
|
+
}),
|
|
851
873
|
value
|
|
852
874
|
});
|
|
853
875
|
}
|
|
@@ -868,7 +890,7 @@ function prepareSubtensorToBase(provider, input) {
|
|
|
868
890
|
}
|
|
869
891
|
|
|
870
892
|
// src/core/transport.ts
|
|
871
|
-
var
|
|
893
|
+
var import_viem7 = require("viem");
|
|
872
894
|
function isRecord(value) {
|
|
873
895
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
874
896
|
}
|
|
@@ -987,10 +1009,38 @@ function providerFromTransport(transport) {
|
|
|
987
1009
|
"An EIP-1193-compatible RPC transport is required."
|
|
988
1010
|
);
|
|
989
1011
|
}
|
|
990
|
-
return
|
|
1012
|
+
return (0, import_viem7.createPublicClient)({
|
|
1013
|
+
transport: (0, import_viem7.custom)(transport, { retryCount: 0 }),
|
|
1014
|
+
cacheTime: 0,
|
|
1015
|
+
batch: { multicall: false }
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
function trackingClient(provider) {
|
|
1019
|
+
if (provider && "getChainId" in provider && typeof provider.getChainId === "function")
|
|
1020
|
+
return provider;
|
|
1021
|
+
if (provider && "send" in provider && typeof provider.send === "function") {
|
|
1022
|
+
return providerFromTransport({
|
|
1023
|
+
request: ({ method, params }) => {
|
|
1024
|
+
if (params !== void 0 && !Array.isArray(params))
|
|
1025
|
+
throw new ForeverMoneyError(
|
|
1026
|
+
"RPC_ERROR",
|
|
1027
|
+
"Tracking RPC params must be an array."
|
|
1028
|
+
);
|
|
1029
|
+
return provider.send(
|
|
1030
|
+
method,
|
|
1031
|
+
params === void 0 ? [] : [...params]
|
|
1032
|
+
);
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
throw new ForeverMoneyError(
|
|
1037
|
+
"MISSING_TRANSPORT",
|
|
1038
|
+
"A viem public client or JSON-RPC provider is required."
|
|
1039
|
+
);
|
|
991
1040
|
}
|
|
992
1041
|
|
|
993
1042
|
// src/core/provider-errors.ts
|
|
1043
|
+
var import_viem8 = require("viem");
|
|
994
1044
|
function stringProperty(value, property) {
|
|
995
1045
|
if (typeof value !== "object" || value === null || !(property in value)) {
|
|
996
1046
|
return void 0;
|
|
@@ -1003,9 +1053,13 @@ async function providerOperation(operation, action) {
|
|
|
1003
1053
|
return await action();
|
|
1004
1054
|
} catch (error) {
|
|
1005
1055
|
if (error instanceof ForeverMoneyError) throw error;
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1008
|
-
|
|
1056
|
+
const revert = error instanceof import_viem8.BaseError ? error.walk(
|
|
1057
|
+
(cause) => cause instanceof import_viem8.ContractFunctionRevertedError || cause instanceof import_viem8.ExecutionRevertedError
|
|
1058
|
+
) : void 0;
|
|
1059
|
+
const viemRevert = revert instanceof import_viem8.ContractFunctionRevertedError || revert instanceof import_viem8.ExecutionRevertedError;
|
|
1060
|
+
const causeCode = viemRevert ? revert.name : stringProperty(error, "code");
|
|
1061
|
+
const reason = viemRevert ? revert instanceof import_viem8.ContractFunctionRevertedError ? revert.data?.errorName ?? revert.reason : void 0 : stringProperty(error, "reason");
|
|
1062
|
+
const reverted = viemRevert || causeCode === "CALL_EXCEPTION";
|
|
1009
1063
|
throw new ForeverMoneyError(
|
|
1010
1064
|
reverted ? "SIMULATION_REVERTED" : "RPC_ERROR",
|
|
1011
1065
|
reverted ? `${operation} reverted.` : `${operation} failed.`,
|
|
@@ -1018,10 +1072,10 @@ async function providerOperation(operation, action) {
|
|
|
1018
1072
|
}
|
|
1019
1073
|
|
|
1020
1074
|
// src/vaults/plans.ts
|
|
1021
|
-
var
|
|
1022
|
-
var
|
|
1023
|
-
var
|
|
1024
|
-
var
|
|
1075
|
+
var import_viem9 = require("viem");
|
|
1076
|
+
var erc20Abi2 = (0, import_viem9.parseAbi)(ERC20_ABI);
|
|
1077
|
+
var factoryAbi = (0, import_viem9.parseAbi)(VAULT_FACTORY_ABI);
|
|
1078
|
+
var managerAbi = (0, import_viem9.parseAbi)(VAULT_MANAGER_ABI);
|
|
1025
1079
|
function step(kind, label, from, to, data, value = 0n) {
|
|
1026
1080
|
return {
|
|
1027
1081
|
kind,
|
|
@@ -1138,10 +1192,11 @@ function buildCreateVaultPlan(input) {
|
|
|
1138
1192
|
`Approve ${stash.token} for the vault factory`,
|
|
1139
1193
|
owner,
|
|
1140
1194
|
stash.token,
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1195
|
+
(0, import_viem9.encodeFunctionData)({
|
|
1196
|
+
abi: erc20Abi2,
|
|
1197
|
+
functionName: "approve",
|
|
1198
|
+
args: [base.contracts.vaultFactory, stash.amount]
|
|
1199
|
+
})
|
|
1145
1200
|
)
|
|
1146
1201
|
);
|
|
1147
1202
|
}
|
|
@@ -1152,15 +1207,19 @@ function buildCreateVaultPlan(input) {
|
|
|
1152
1207
|
"Create ForeverMoney vault",
|
|
1153
1208
|
owner,
|
|
1154
1209
|
base.contracts.vaultFactory,
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1210
|
+
(0, import_viem9.encodeFunctionData)({
|
|
1211
|
+
abi: factoryAbi,
|
|
1212
|
+
functionName: "create",
|
|
1213
|
+
args: [
|
|
1214
|
+
owner,
|
|
1215
|
+
associatedMiner,
|
|
1216
|
+
akAddress,
|
|
1217
|
+
poolManager,
|
|
1218
|
+
poolAddress,
|
|
1219
|
+
positionManagerImplementation,
|
|
1220
|
+
stashTokens
|
|
1221
|
+
]
|
|
1222
|
+
}),
|
|
1164
1223
|
value
|
|
1165
1224
|
)
|
|
1166
1225
|
);
|
|
@@ -1179,14 +1238,15 @@ async function prepareCreateVault(provider, input) {
|
|
|
1179
1238
|
const allowances = await Promise.all(
|
|
1180
1239
|
erc20Stash.map(async ({ token }) => ({
|
|
1181
1240
|
token,
|
|
1182
|
-
allowance: await
|
|
1183
|
-
token,
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1241
|
+
allowance: await provider.readContract({
|
|
1242
|
+
address: token,
|
|
1243
|
+
abi: erc20Abi2,
|
|
1244
|
+
functionName: "allowance",
|
|
1245
|
+
args: [
|
|
1246
|
+
owner,
|
|
1247
|
+
foreverMoneyDeployment.base.contracts.vaultFactory
|
|
1248
|
+
]
|
|
1249
|
+
})
|
|
1190
1250
|
}))
|
|
1191
1251
|
);
|
|
1192
1252
|
return buildCreateVaultPlan({ ...input, allowances });
|
|
@@ -1213,11 +1273,11 @@ function buildDepositVaultPlan(input) {
|
|
|
1213
1273
|
"Deposit native ETH into the vault as WETH",
|
|
1214
1274
|
owner,
|
|
1215
1275
|
manager,
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
deposit.amount
|
|
1220
|
-
|
|
1276
|
+
(0, import_viem9.encodeFunctionData)({
|
|
1277
|
+
abi: managerAbi,
|
|
1278
|
+
functionName: "topUpAk",
|
|
1279
|
+
args: [akAddress, import_viem9.zeroAddress, deposit.amount]
|
|
1280
|
+
}),
|
|
1221
1281
|
deposit.amount
|
|
1222
1282
|
)
|
|
1223
1283
|
);
|
|
@@ -1237,10 +1297,11 @@ function buildDepositVaultPlan(input) {
|
|
|
1237
1297
|
`Approve ${deposit.token} for the vault manager`,
|
|
1238
1298
|
owner,
|
|
1239
1299
|
deposit.token,
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1300
|
+
(0, import_viem9.encodeFunctionData)({
|
|
1301
|
+
abi: erc20Abi2,
|
|
1302
|
+
functionName: "approve",
|
|
1303
|
+
args: [manager, deposit.amount]
|
|
1304
|
+
})
|
|
1244
1305
|
)
|
|
1245
1306
|
);
|
|
1246
1307
|
}
|
|
@@ -1250,11 +1311,11 @@ function buildDepositVaultPlan(input) {
|
|
|
1250
1311
|
`Deposit ${deposit.token} into the vault`,
|
|
1251
1312
|
owner,
|
|
1252
1313
|
manager,
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
deposit.amount
|
|
1257
|
-
|
|
1314
|
+
(0, import_viem9.encodeFunctionData)({
|
|
1315
|
+
abi: managerAbi,
|
|
1316
|
+
functionName: "topUpAk",
|
|
1317
|
+
args: [akAddress, deposit.token, deposit.amount]
|
|
1318
|
+
})
|
|
1258
1319
|
)
|
|
1259
1320
|
);
|
|
1260
1321
|
}
|
|
@@ -1274,11 +1335,12 @@ async function prepareDepositVault(provider, input) {
|
|
|
1274
1335
|
const allowances = await Promise.all(
|
|
1275
1336
|
erc20Deposits.map(async ({ token }) => ({
|
|
1276
1337
|
token,
|
|
1277
|
-
allowance: await
|
|
1278
|
-
token,
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1338
|
+
allowance: await provider.readContract({
|
|
1339
|
+
address: token,
|
|
1340
|
+
abi: erc20Abi2,
|
|
1341
|
+
functionName: "allowance",
|
|
1342
|
+
args: [owner, manager]
|
|
1343
|
+
})
|
|
1282
1344
|
}))
|
|
1283
1345
|
);
|
|
1284
1346
|
return buildDepositVaultPlan({ ...input, allowances });
|
|
@@ -1309,16 +1371,17 @@ function buildWithdrawVaultPlan(input) {
|
|
|
1309
1371
|
"Withdraw assets from the vault",
|
|
1310
1372
|
owner,
|
|
1311
1373
|
manager,
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1374
|
+
(0, import_viem9.encodeFunctionData)({
|
|
1375
|
+
abi: managerAbi,
|
|
1376
|
+
functionName: "withdrawFromAkAndPositions",
|
|
1377
|
+
args: [
|
|
1315
1378
|
akAddress,
|
|
1316
1379
|
input.amount0,
|
|
1317
1380
|
input.amount1,
|
|
1318
1381
|
input.decreaseTokenIds,
|
|
1319
1382
|
input.unwrapWeth
|
|
1320
1383
|
]
|
|
1321
|
-
)
|
|
1384
|
+
})
|
|
1322
1385
|
)
|
|
1323
1386
|
]
|
|
1324
1387
|
});
|
|
@@ -1336,9 +1399,11 @@ function buildClaimVaultFeesPlan(input) {
|
|
|
1336
1399
|
"Claim vault fees",
|
|
1337
1400
|
owner,
|
|
1338
1401
|
manager,
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1402
|
+
(0, import_viem9.encodeFunctionData)({
|
|
1403
|
+
abi: managerAbi,
|
|
1404
|
+
functionName: "claimFees",
|
|
1405
|
+
args: [akAddress]
|
|
1406
|
+
})
|
|
1342
1407
|
)
|
|
1343
1408
|
]
|
|
1344
1409
|
});
|
|
@@ -1358,20 +1423,21 @@ function buildSetVaultStakingPlan(input) {
|
|
|
1358
1423
|
`${input.staking ? "Stake" : "Unstake"} the vault position`,
|
|
1359
1424
|
owner,
|
|
1360
1425
|
manager,
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1426
|
+
(0, import_viem9.encodeFunctionData)({
|
|
1427
|
+
abi: managerAbi,
|
|
1428
|
+
functionName: action,
|
|
1429
|
+
args: [akAddress, "0x"]
|
|
1430
|
+
})
|
|
1365
1431
|
)
|
|
1366
1432
|
]
|
|
1367
1433
|
});
|
|
1368
1434
|
}
|
|
1369
1435
|
|
|
1370
1436
|
// src/bridge/tracking.ts
|
|
1371
|
-
var
|
|
1437
|
+
var import_viem11 = require("viem");
|
|
1372
1438
|
|
|
1373
1439
|
// src/bridge/receipts.ts
|
|
1374
|
-
var
|
|
1440
|
+
var import_viem10 = require("viem");
|
|
1375
1441
|
|
|
1376
1442
|
// src/core/receipts.ts
|
|
1377
1443
|
function isLogFrom(log, address) {
|
|
@@ -1379,8 +1445,8 @@ function isLogFrom(log, address) {
|
|
|
1379
1445
|
}
|
|
1380
1446
|
|
|
1381
1447
|
// src/bridge/receipts.ts
|
|
1382
|
-
var
|
|
1383
|
-
var
|
|
1448
|
+
var alphaGatewayAbi = (0, import_viem10.parseAbi)(ALPHA_GATEWAY_ABI);
|
|
1449
|
+
var spokeGatewayAbi = (0, import_viem10.parseAbi)(SPOKE_GATEWAY_ABI);
|
|
1384
1450
|
function assertBridgeDirection(value) {
|
|
1385
1451
|
if (value !== "base-to-subtensor" && value !== "robinhood-to-subtensor" && value !== "subtensor-to-base" && value !== "subtensor-to-robinhood") {
|
|
1386
1452
|
throw new ForeverMoneyError(
|
|
@@ -1403,20 +1469,21 @@ function bridgeMessageIdFromReceipt(direction, receipt) {
|
|
|
1403
1469
|
evmChainFromBridgeDirection(direction)
|
|
1404
1470
|
);
|
|
1405
1471
|
const evmToSubtensor = isEvmToSubtensorDirection(direction);
|
|
1406
|
-
const [address,
|
|
1472
|
+
const [address, contractAbi, eventName] = evmToSubtensor ? [evm.contracts.gateway, spokeGatewayAbi, "BridgedToFinney"] : [
|
|
1407
1473
|
foreverMoneyDeployment.subtensor.contracts.gateway,
|
|
1408
|
-
|
|
1474
|
+
alphaGatewayAbi,
|
|
1409
1475
|
"BridgedOut"
|
|
1410
1476
|
];
|
|
1411
1477
|
for (const log of receipt.logs) {
|
|
1412
1478
|
if (!isLogFrom(log, address)) continue;
|
|
1413
1479
|
try {
|
|
1414
|
-
const parsed =
|
|
1480
|
+
const parsed = (0, import_viem10.decodeEventLog)({
|
|
1481
|
+
abi: contractAbi,
|
|
1415
1482
|
data: log.data,
|
|
1416
1483
|
topics: [...log.topics]
|
|
1417
1484
|
});
|
|
1418
|
-
const messageId = parsed
|
|
1419
|
-
if (parsed
|
|
1485
|
+
const messageId = "messageId" in parsed.args ? parsed.args.messageId : void 0;
|
|
1486
|
+
if (parsed.eventName === eventName && typeof messageId === "string" && (0, import_viem10.isHex)(messageId, { strict: true }) && messageId.length === 66 && (evmToSubtensor || "destChainSelector" in parsed.args && parsed.args.destChainSelector === evm.ccipSelector)) {
|
|
1420
1487
|
return messageId.toLowerCase();
|
|
1421
1488
|
}
|
|
1422
1489
|
} catch {
|
|
@@ -1426,8 +1493,8 @@ function bridgeMessageIdFromReceipt(direction, receipt) {
|
|
|
1426
1493
|
}
|
|
1427
1494
|
|
|
1428
1495
|
// src/bridge/tracking.ts
|
|
1429
|
-
var
|
|
1430
|
-
var
|
|
1496
|
+
var ccipExecutionAbi = (0, import_viem11.parseAbi)(CCIP_EXECUTION_ABI);
|
|
1497
|
+
var alphaGatewayAbi2 = (0, import_viem11.parseAbi)(ALPHA_GATEWAY_ABI);
|
|
1431
1498
|
function destinationChainId(direction) {
|
|
1432
1499
|
assertBridgeDirection(direction);
|
|
1433
1500
|
const evm = getForeverMoneyEvmDeployment(
|
|
@@ -1443,14 +1510,14 @@ function sourceChainId(direction) {
|
|
|
1443
1510
|
return isEvmToSubtensorDirection(direction) ? evm.chainId : foreverMoneyDeployment.subtensor.chainId;
|
|
1444
1511
|
}
|
|
1445
1512
|
async function assertProviderChain(provider, expectedChainId, label) {
|
|
1446
|
-
const
|
|
1447
|
-
if (
|
|
1513
|
+
const chainId = await provider.getChainId();
|
|
1514
|
+
if (chainId !== expectedChainId) {
|
|
1448
1515
|
throw new ForeverMoneyError(
|
|
1449
1516
|
"CHAIN_MISMATCH",
|
|
1450
|
-
`${label} transport reported chain ID ${
|
|
1517
|
+
`${label} transport reported chain ID ${chainId}; expected ${expectedChainId}.`,
|
|
1451
1518
|
{
|
|
1452
1519
|
expectedChainId,
|
|
1453
|
-
actualChainId:
|
|
1520
|
+
actualChainId: chainId.toString()
|
|
1454
1521
|
}
|
|
1455
1522
|
);
|
|
1456
1523
|
}
|
|
@@ -1461,13 +1528,14 @@ async function assertDestinationProvider(provider, direction) {
|
|
|
1461
1528
|
return expectedChainId;
|
|
1462
1529
|
}
|
|
1463
1530
|
async function getBridgeSourceStatus(provider, input) {
|
|
1531
|
+
const client = trackingClient(provider);
|
|
1464
1532
|
const expectedChainId = sourceChainId(input.direction);
|
|
1465
1533
|
const transactionHash = normalizeBytes32(
|
|
1466
1534
|
input.transactionHash,
|
|
1467
1535
|
"Transaction hash"
|
|
1468
1536
|
);
|
|
1469
|
-
await assertProviderChain(
|
|
1470
|
-
const receipt = await
|
|
1537
|
+
await assertProviderChain(client, expectedChainId, "Bridge source");
|
|
1538
|
+
const receipt = await receiptOrNull(client, transactionHash);
|
|
1471
1539
|
if (receipt === null) {
|
|
1472
1540
|
return Object.freeze({
|
|
1473
1541
|
direction: input.direction,
|
|
@@ -1477,7 +1545,7 @@ async function getBridgeSourceStatus(provider, input) {
|
|
|
1477
1545
|
messageId: null
|
|
1478
1546
|
});
|
|
1479
1547
|
}
|
|
1480
|
-
if (receipt.status ===
|
|
1548
|
+
if (receipt.status === "reverted") {
|
|
1481
1549
|
return Object.freeze({
|
|
1482
1550
|
direction: input.direction,
|
|
1483
1551
|
sourceChainId: expectedChainId,
|
|
@@ -1486,7 +1554,7 @@ async function getBridgeSourceStatus(provider, input) {
|
|
|
1486
1554
|
messageId: null
|
|
1487
1555
|
});
|
|
1488
1556
|
}
|
|
1489
|
-
if (receipt.status !==
|
|
1557
|
+
if (receipt.status !== "success") {
|
|
1490
1558
|
throw new ForeverMoneyError(
|
|
1491
1559
|
"INVALID_PROVIDER_RESPONSE",
|
|
1492
1560
|
"The bridge source receipt has an invalid status."
|
|
@@ -1508,8 +1576,10 @@ async function getBridgeSourceStatus(provider, input) {
|
|
|
1508
1576
|
});
|
|
1509
1577
|
}
|
|
1510
1578
|
async function getCcipDeliveryCheckpoint(provider, direction) {
|
|
1511
|
-
const
|
|
1512
|
-
const
|
|
1579
|
+
const client = trackingClient(provider);
|
|
1580
|
+
const expectedChainId = await assertDestinationProvider(client, direction);
|
|
1581
|
+
const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
|
|
1582
|
+
const fromBlock = Number(blockNumber);
|
|
1513
1583
|
if (!Number.isSafeInteger(fromBlock) || fromBlock < 0) {
|
|
1514
1584
|
throw new ForeverMoneyError(
|
|
1515
1585
|
"INVALID_PROVIDER_RESPONSE",
|
|
@@ -1523,6 +1593,7 @@ async function getCcipDeliveryCheckpoint(provider, direction) {
|
|
|
1523
1593
|
});
|
|
1524
1594
|
}
|
|
1525
1595
|
async function getCcipDeliveryStatus(provider, input) {
|
|
1596
|
+
const client = trackingClient(provider);
|
|
1526
1597
|
const expectedChainId = destinationChainId(input.direction);
|
|
1527
1598
|
const messageId = normalizeBytes32(input.messageId, "CCIP message ID");
|
|
1528
1599
|
if (!Number.isSafeInteger(input.fromBlock) || input.fromBlock < 0) {
|
|
@@ -1531,30 +1602,27 @@ async function getCcipDeliveryStatus(provider, input) {
|
|
|
1531
1602
|
"CCIP fromBlock must be a non-negative safe integer."
|
|
1532
1603
|
);
|
|
1533
1604
|
}
|
|
1534
|
-
await assertProviderChain(
|
|
1535
|
-
const event = ccipExecutionInterface.getEvent("ExecutionStateChanged");
|
|
1536
|
-
if (event === null) {
|
|
1537
|
-
throw new Error("CCIP execution event is missing from the SDK ABI.");
|
|
1538
|
-
}
|
|
1605
|
+
await assertProviderChain(client, expectedChainId, "Bridge destination");
|
|
1539
1606
|
const evmChain = evmChainFromBridgeDirection(input.direction);
|
|
1540
1607
|
const evm = getForeverMoneyEvmDeployment(evmChain);
|
|
1541
1608
|
const evmToSubtensor = isEvmToSubtensorDirection(input.direction);
|
|
1542
1609
|
const sourceSelector = evmToSubtensor ? evm.ccipSelector : foreverMoneyDeployment.subtensor.ccipSelector;
|
|
1543
1610
|
const offRamp = evmToSubtensor ? evmChain === "base" ? foreverMoneyDeployment.subtensor.contracts.ccipOffRampFromBase : foreverMoneyDeployment.subtensor.contracts.ccipOffRampFromRobinhood : evm.contracts.ccipOffRampFromSubtensor;
|
|
1544
|
-
const logs = await
|
|
1611
|
+
const logs = await client.getLogs({
|
|
1545
1612
|
address: offRamp,
|
|
1546
|
-
fromBlock: input.fromBlock,
|
|
1613
|
+
fromBlock: BigInt(input.fromBlock),
|
|
1547
1614
|
toBlock: "latest",
|
|
1548
|
-
|
|
1615
|
+
event: ccipExecutionAbi[0],
|
|
1616
|
+
args: { sourceChainSelector: sourceSelector, messageId },
|
|
1617
|
+
strict: true
|
|
1549
1618
|
});
|
|
1550
1619
|
const latest = logs.at(-1);
|
|
1551
1620
|
if (latest === void 0) return "waiting";
|
|
1552
|
-
const
|
|
1553
|
-
const state = Number(parsed?.args.state);
|
|
1621
|
+
const state = latest.args.state;
|
|
1554
1622
|
if (state === 3) return "failure";
|
|
1555
1623
|
if (state !== 2) return "waiting";
|
|
1556
1624
|
if (!evmToSubtensor) return "success";
|
|
1557
|
-
const receipt = await
|
|
1625
|
+
const receipt = await receiptOrNull(client, latest.transactionHash);
|
|
1558
1626
|
if (receipt === null) {
|
|
1559
1627
|
throw new ForeverMoneyError(
|
|
1560
1628
|
"INVALID_PROVIDER_RESPONSE",
|
|
@@ -1566,7 +1634,11 @@ async function getCcipDeliveryStatus(provider, input) {
|
|
|
1566
1634
|
continue;
|
|
1567
1635
|
}
|
|
1568
1636
|
try {
|
|
1569
|
-
if (
|
|
1637
|
+
if ((0, import_viem11.decodeEventLog)({
|
|
1638
|
+
abi: alphaGatewayAbi2,
|
|
1639
|
+
data: log.data,
|
|
1640
|
+
topics: log.topics
|
|
1641
|
+
}).eventName === "Claimable") {
|
|
1570
1642
|
return "recovery";
|
|
1571
1643
|
}
|
|
1572
1644
|
} catch {
|
|
@@ -1574,20 +1646,28 @@ async function getCcipDeliveryStatus(provider, input) {
|
|
|
1574
1646
|
}
|
|
1575
1647
|
return "success";
|
|
1576
1648
|
}
|
|
1649
|
+
async function receiptOrNull(provider, hash) {
|
|
1650
|
+
try {
|
|
1651
|
+
return await provider.getTransactionReceipt({ hash });
|
|
1652
|
+
} catch (error) {
|
|
1653
|
+
if (error instanceof import_viem11.TransactionReceiptNotFoundError) return null;
|
|
1654
|
+
throw error;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1577
1657
|
|
|
1578
1658
|
// src/client.ts
|
|
1579
1659
|
async function assertProviderChain2(provider, expectedChainId, name) {
|
|
1580
|
-
const
|
|
1660
|
+
const chainId = await providerOperation(
|
|
1581
1661
|
`Reading the ${name} chain ID`,
|
|
1582
|
-
() => provider.
|
|
1662
|
+
() => provider.getChainId()
|
|
1583
1663
|
);
|
|
1584
|
-
if (
|
|
1664
|
+
if (chainId !== expectedChainId) {
|
|
1585
1665
|
throw new ForeverMoneyError(
|
|
1586
1666
|
"CHAIN_MISMATCH",
|
|
1587
|
-
`${name} transport reported chain ID ${
|
|
1667
|
+
`${name} transport reported chain ID ${chainId}; expected ${expectedChainId}.`,
|
|
1588
1668
|
{
|
|
1589
1669
|
expectedChainId,
|
|
1590
|
-
actualChainId:
|
|
1670
|
+
actualChainId: chainId.toString()
|
|
1591
1671
|
}
|
|
1592
1672
|
);
|
|
1593
1673
|
}
|
|
@@ -1719,19 +1799,20 @@ function createForeverMoneyClient(options) {
|
|
|
1719
1799
|
}
|
|
1720
1800
|
|
|
1721
1801
|
// src/vaults/receipts.ts
|
|
1722
|
-
var
|
|
1723
|
-
var
|
|
1802
|
+
var import_viem12 = require("viem");
|
|
1803
|
+
var vaultFactoryAbi = (0, import_viem12.parseAbi)(VAULT_FACTORY_ABI);
|
|
1724
1804
|
function vaultManagerFromCreationReceipt(receipt) {
|
|
1725
1805
|
for (const log of receipt.logs) {
|
|
1726
1806
|
if (!isLogFrom(log, foreverMoneyDeployment.base.contracts.vaultFactory)) {
|
|
1727
1807
|
continue;
|
|
1728
1808
|
}
|
|
1729
1809
|
try {
|
|
1730
|
-
const parsed =
|
|
1810
|
+
const parsed = (0, import_viem12.decodeEventLog)({
|
|
1811
|
+
abi: vaultFactoryAbi,
|
|
1731
1812
|
data: log.data,
|
|
1732
1813
|
topics: [...log.topics]
|
|
1733
1814
|
});
|
|
1734
|
-
if (parsed
|
|
1815
|
+
if (parsed.eventName === "SnLiquidityManagerCreated") {
|
|
1735
1816
|
return normalizeEvmAddress(String(parsed.args.manager));
|
|
1736
1817
|
}
|
|
1737
1818
|
} catch {
|
|
@@ -1741,7 +1822,7 @@ function vaultManagerFromCreationReceipt(receipt) {
|
|
|
1741
1822
|
}
|
|
1742
1823
|
|
|
1743
1824
|
// src/core/transactions.ts
|
|
1744
|
-
var
|
|
1825
|
+
var import_viem13 = require("viem");
|
|
1745
1826
|
function decimalQuantity(value, label) {
|
|
1746
1827
|
if (!/^(0|[1-9][0-9]*)$/.test(value)) {
|
|
1747
1828
|
throw new ForeverMoneyError(
|
|
@@ -1750,7 +1831,7 @@ function decimalQuantity(value, label) {
|
|
|
1750
1831
|
);
|
|
1751
1832
|
}
|
|
1752
1833
|
const quantity = BigInt(value);
|
|
1753
|
-
if (quantity >
|
|
1834
|
+
if (quantity > import_viem13.maxUint256) {
|
|
1754
1835
|
throw new ForeverMoneyError(
|
|
1755
1836
|
"INVALID_TRANSACTION_PLAN",
|
|
1756
1837
|
`${label} exceeds uint256.`
|
|
@@ -1786,4 +1867,50 @@ function toEthersTransaction(transaction) {
|
|
|
1786
1867
|
}
|
|
1787
1868
|
});
|
|
1788
1869
|
}
|
|
1870
|
+
var transactionChains = new Map(
|
|
1871
|
+
[
|
|
1872
|
+
[BASE_CHAIN_ID, "Base", "Ether", "ETH"],
|
|
1873
|
+
[ROBINHOOD_CHAIN_ID, "Robinhood", "Ether", "ETH"],
|
|
1874
|
+
[SUBTENSOR_CHAIN_ID, "Subtensor", "TAO", "TAO"]
|
|
1875
|
+
].map(([id, name, currency, symbol]) => [
|
|
1876
|
+
id,
|
|
1877
|
+
Object.freeze(
|
|
1878
|
+
(0, import_viem13.defineChain)({
|
|
1879
|
+
id,
|
|
1880
|
+
name,
|
|
1881
|
+
nativeCurrency: Object.freeze({
|
|
1882
|
+
name: currency,
|
|
1883
|
+
symbol,
|
|
1884
|
+
decimals: 18
|
|
1885
|
+
}),
|
|
1886
|
+
// Chain identity only. The caller retains ownership of the wallet transport.
|
|
1887
|
+
rpcUrls: Object.freeze({
|
|
1888
|
+
default: Object.freeze({ http: Object.freeze([]) })
|
|
1889
|
+
})
|
|
1890
|
+
})
|
|
1891
|
+
)
|
|
1892
|
+
])
|
|
1893
|
+
);
|
|
1894
|
+
function toViemTransaction(transaction) {
|
|
1895
|
+
const chain = transactionChains.get(transaction.chainId);
|
|
1896
|
+
if (!chain)
|
|
1897
|
+
throw new ForeverMoneyError(
|
|
1898
|
+
"INVALID_TRANSACTION_PLAN",
|
|
1899
|
+
"Unsupported transaction chain."
|
|
1900
|
+
);
|
|
1901
|
+
return Object.freeze({
|
|
1902
|
+
chain,
|
|
1903
|
+
account: transaction.from,
|
|
1904
|
+
chainId: transaction.chainId,
|
|
1905
|
+
to: transaction.to,
|
|
1906
|
+
data: transaction.data,
|
|
1907
|
+
value: decimalQuantity(transaction.value, "Transaction value"),
|
|
1908
|
+
...transaction.gasLimit === void 0 ? {} : {
|
|
1909
|
+
gas: decimalQuantity(
|
|
1910
|
+
transaction.gasLimit,
|
|
1911
|
+
"Transaction gas limit"
|
|
1912
|
+
)
|
|
1913
|
+
}
|
|
1914
|
+
});
|
|
1915
|
+
}
|
|
1789
1916
|
//# sourceMappingURL=index.cjs.map
|