@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.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
// src/core/addresses.ts
|
|
2
|
-
import { isHex, u8aToHex } from "@polkadot/util";
|
|
3
2
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from "@polkadot/
|
|
8
|
-
import {
|
|
3
|
+
AccountId,
|
|
4
|
+
Blake2256,
|
|
5
|
+
getSs58AddressInfo
|
|
6
|
+
} from "@polkadot-api/substrate-bindings";
|
|
7
|
+
import {
|
|
8
|
+
bytesToHex,
|
|
9
|
+
concat,
|
|
10
|
+
getAddress,
|
|
11
|
+
hexToBytes,
|
|
12
|
+
isAddress,
|
|
13
|
+
stringToBytes,
|
|
14
|
+
zeroAddress
|
|
15
|
+
} from "viem";
|
|
9
16
|
|
|
10
17
|
// src/core/errors.ts
|
|
11
18
|
var ForeverMoneyError = class extends Error {
|
|
@@ -22,22 +29,33 @@ var ForeverMoneyError = class extends Error {
|
|
|
22
29
|
// src/core/addresses.ts
|
|
23
30
|
var BITTENSOR_SS58_PREFIX = 42;
|
|
24
31
|
function normalizeEvmAddress(value) {
|
|
25
|
-
|
|
32
|
+
const candidate = typeof value === "string" && /^0x[0-9A-F]{40}$/.test(value) ? value.toLowerCase() : value;
|
|
33
|
+
if (!isAddress(candidate) || candidate === zeroAddress) {
|
|
26
34
|
throw new ForeverMoneyError(
|
|
27
35
|
"INVALID_ADDRESS",
|
|
28
36
|
"Expected a non-zero EVM address."
|
|
29
37
|
);
|
|
30
38
|
}
|
|
31
|
-
return getAddress(
|
|
39
|
+
return getAddress(candidate);
|
|
32
40
|
}
|
|
33
41
|
function evmToMirrorSS58(evmAddress) {
|
|
34
|
-
return
|
|
42
|
+
return AccountId(BITTENSOR_SS58_PREFIX).dec(
|
|
43
|
+
Blake2256(
|
|
44
|
+
concat([
|
|
45
|
+
stringToBytes("evm:"),
|
|
46
|
+
hexToBytes(normalizeEvmAddress(evmAddress))
|
|
47
|
+
])
|
|
48
|
+
)
|
|
49
|
+
);
|
|
35
50
|
}
|
|
36
51
|
function decodeBittensorAddress(value) {
|
|
37
52
|
try {
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
if (typeof value !== "string" || !value || value.startsWith("0x"))
|
|
54
|
+
throw new Error("Raw hex is not SS58.");
|
|
55
|
+
const info = getSs58AddressInfo(value);
|
|
56
|
+
if (!info.isValid || info.ss58Format !== BITTENSOR_SS58_PREFIX || info.publicKey.length !== 32)
|
|
57
|
+
throw new Error("Invalid Bittensor address.");
|
|
58
|
+
const publicKey = info.publicKey;
|
|
41
59
|
return publicKey;
|
|
42
60
|
} catch {
|
|
43
61
|
throw new ForeverMoneyError(
|
|
@@ -47,7 +65,7 @@ function decodeBittensorAddress(value) {
|
|
|
47
65
|
}
|
|
48
66
|
}
|
|
49
67
|
function normalizeSS58(value) {
|
|
50
|
-
return
|
|
68
|
+
return AccountId(BITTENSOR_SS58_PREFIX).dec(decodeBittensorAddress(value));
|
|
51
69
|
}
|
|
52
70
|
function isBittensorSS58(value) {
|
|
53
71
|
try {
|
|
@@ -58,14 +76,14 @@ function isBittensorSS58(value) {
|
|
|
58
76
|
}
|
|
59
77
|
}
|
|
60
78
|
function ss58ToPublicKey(value) {
|
|
61
|
-
return
|
|
79
|
+
return bytesToHex(decodeBittensorAddress(value));
|
|
62
80
|
}
|
|
63
81
|
|
|
64
82
|
// src/core/amounts.ts
|
|
65
|
-
import {
|
|
83
|
+
import { maxUint256, formatUnits, parseUnits } from "viem";
|
|
66
84
|
|
|
67
85
|
// src/chains/deployment.ts
|
|
68
|
-
import { getAddress as getAddress2 } from "
|
|
86
|
+
import { getAddress as getAddress2 } from "viem";
|
|
69
87
|
var BASE_CHAIN_ID = 8453;
|
|
70
88
|
var ROBINHOOD_CHAIN_ID = 4663;
|
|
71
89
|
var SUBTENSOR_CHAIN_ID = 964;
|
|
@@ -203,7 +221,7 @@ function assertWholeRao(amountWei) {
|
|
|
203
221
|
"The amount cannot be negative."
|
|
204
222
|
);
|
|
205
223
|
}
|
|
206
|
-
if (amountWei >
|
|
224
|
+
if (amountWei > maxUint256) {
|
|
207
225
|
throw new ForeverMoneyError(
|
|
208
226
|
"INVALID_TRANSACTION_PLAN",
|
|
209
227
|
"The amount exceeds uint256."
|
|
@@ -229,7 +247,7 @@ function formatTaoAmount(amountWei) {
|
|
|
229
247
|
"A TAO amount cannot be negative."
|
|
230
248
|
);
|
|
231
249
|
}
|
|
232
|
-
if (amountWei >
|
|
250
|
+
if (amountWei > maxUint256) {
|
|
233
251
|
throw new ForeverMoneyError(
|
|
234
252
|
"INVALID_TRANSACTION_PLAN",
|
|
235
253
|
"The TAO amount exceeds uint256."
|
|
@@ -241,7 +259,8 @@ function formatTaoAmount(amountWei) {
|
|
|
241
259
|
"TAO amounts must resolve to a whole RAO."
|
|
242
260
|
);
|
|
243
261
|
}
|
|
244
|
-
|
|
262
|
+
const formatted = formatUnits(amountWei, 18);
|
|
263
|
+
return formatted.includes(".") ? formatted : `${formatted}.0`;
|
|
245
264
|
}
|
|
246
265
|
function mulDivCeil(value, numerator, denominator) {
|
|
247
266
|
return (value * numerator + denominator - 1n) / denominator;
|
|
@@ -264,7 +283,7 @@ function feeWithBuffer(fee) {
|
|
|
264
283
|
BASIS_POINTS + NETWORK_FEE_BUFFER_BPS,
|
|
265
284
|
BASIS_POINTS
|
|
266
285
|
);
|
|
267
|
-
if (buffered >
|
|
286
|
+
if (buffered > maxUint256) {
|
|
268
287
|
throw new ForeverMoneyError(
|
|
269
288
|
"INVALID_TRANSACTION_PLAN",
|
|
270
289
|
"The buffered network fee exceeds uint256."
|
|
@@ -290,7 +309,7 @@ function gasLimitWithBuffer(gasLimit) {
|
|
|
290
309
|
BASIS_POINTS + GAS_LIMIT_BUFFER_BPS,
|
|
291
310
|
BASIS_POINTS
|
|
292
311
|
);
|
|
293
|
-
if (buffered >
|
|
312
|
+
if (buffered > maxUint256) {
|
|
294
313
|
throw new ForeverMoneyError(
|
|
295
314
|
"INVALID_TRANSACTION_PLAN",
|
|
296
315
|
"The buffered gas limit exceeds uint256."
|
|
@@ -374,10 +393,10 @@ var foreverMoneyAbis = Object.freeze({
|
|
|
374
393
|
});
|
|
375
394
|
|
|
376
395
|
// src/bridge/plans.ts
|
|
377
|
-
import {
|
|
396
|
+
import { encodeFunctionData, parseAbi } from "viem";
|
|
378
397
|
|
|
379
398
|
// src/core/plans.ts
|
|
380
|
-
import { keccak256,
|
|
399
|
+
import { keccak256, stringToBytes as stringToBytes2 } from "viem";
|
|
381
400
|
function createTransactionPlan(plan) {
|
|
382
401
|
const steps = plan.steps.map(
|
|
383
402
|
(step2) => Object.freeze({
|
|
@@ -394,12 +413,12 @@ function createTransactionPlan(plan) {
|
|
|
394
413
|
};
|
|
395
414
|
return Object.freeze({
|
|
396
415
|
...versionedPlan,
|
|
397
|
-
hash: keccak256(
|
|
416
|
+
hash: keccak256(stringToBytes2(JSON.stringify(versionedPlan)))
|
|
398
417
|
});
|
|
399
418
|
}
|
|
400
419
|
|
|
401
420
|
// src/core/validation.ts
|
|
402
|
-
import {
|
|
421
|
+
import { maxUint256 as maxUint2562, zeroHash, isHex } from "viem";
|
|
403
422
|
function assertBigInt(amount, label) {
|
|
404
423
|
if (typeof amount !== "bigint") {
|
|
405
424
|
throw new ForeverMoneyError(
|
|
@@ -422,7 +441,7 @@ function assertPositiveAmount(amount, label) {
|
|
|
422
441
|
`${label} cannot be negative.`
|
|
423
442
|
);
|
|
424
443
|
}
|
|
425
|
-
if (amount >
|
|
444
|
+
if (amount > maxUint2562) {
|
|
426
445
|
throw new ForeverMoneyError(
|
|
427
446
|
"INVALID_TRANSACTION_PLAN",
|
|
428
447
|
`${label} exceeds uint256.`
|
|
@@ -437,7 +456,7 @@ function assertNonNegativeAmount(amount, label) {
|
|
|
437
456
|
`${label} cannot be negative.`
|
|
438
457
|
);
|
|
439
458
|
}
|
|
440
|
-
if (amount >
|
|
459
|
+
if (amount > maxUint2562) {
|
|
441
460
|
throw new ForeverMoneyError(
|
|
442
461
|
"INVALID_TRANSACTION_PLAN",
|
|
443
462
|
`${label} exceeds uint256.`
|
|
@@ -469,7 +488,7 @@ function assertRecord(value, label) {
|
|
|
469
488
|
}
|
|
470
489
|
}
|
|
471
490
|
function normalizeBytes32(value, label) {
|
|
472
|
-
if (!
|
|
491
|
+
if (!isHex(value, { strict: true }) || value.length !== 66) {
|
|
473
492
|
throw new ForeverMoneyError(
|
|
474
493
|
"INVALID_BYTES32",
|
|
475
494
|
`${label} must be a 32-byte hex value.`
|
|
@@ -478,14 +497,14 @@ function normalizeBytes32(value, label) {
|
|
|
478
497
|
return value.toLowerCase();
|
|
479
498
|
}
|
|
480
499
|
function normalizeOptionalBytes32(value, label) {
|
|
481
|
-
return value === void 0 ?
|
|
500
|
+
return value === void 0 ? zeroHash : normalizeBytes32(value, label);
|
|
482
501
|
}
|
|
483
502
|
|
|
484
503
|
// src/bridge/plans.ts
|
|
485
|
-
var
|
|
486
|
-
var
|
|
487
|
-
var
|
|
488
|
-
var
|
|
504
|
+
var erc20Abi = parseAbi(ERC20_ABI);
|
|
505
|
+
var spokeAbi = parseAbi(SPOKE_GATEWAY_ABI);
|
|
506
|
+
var alphaAbi = parseAbi(ALPHA_GATEWAY_ABI);
|
|
507
|
+
var stakingAbi = parseAbi(STAKING_ABI);
|
|
489
508
|
var MIN_LIQUID_EVM_TO_SUBTENSOR_WEI = 10000000000000000n;
|
|
490
509
|
var MIN_LIQUID_BASE_TO_SUBTENSOR_WEI = MIN_LIQUID_EVM_TO_SUBTENSOR_WEI;
|
|
491
510
|
function assertDelivery(value) {
|
|
@@ -554,10 +573,11 @@ function buildEvmToSubtensorPlan(input) {
|
|
|
554
573
|
evm.chainId,
|
|
555
574
|
sender,
|
|
556
575
|
evm.contracts.wrappedTao,
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
576
|
+
encodeFunctionData({
|
|
577
|
+
abi: erc20Abi,
|
|
578
|
+
functionName: "approve",
|
|
579
|
+
args: [evm.contracts.gateway, input.amountWei]
|
|
580
|
+
}),
|
|
561
581
|
0n
|
|
562
582
|
)
|
|
563
583
|
);
|
|
@@ -570,10 +590,11 @@ function buildEvmToSubtensorPlan(input) {
|
|
|
570
590
|
evm.chainId,
|
|
571
591
|
sender,
|
|
572
592
|
evm.contracts.gateway,
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
593
|
+
encodeFunctionData({
|
|
594
|
+
abi: spokeAbi,
|
|
595
|
+
functionName: "bridgeToFinney",
|
|
596
|
+
args: [evm.contracts.wrappedTao, input.amountWei, exit]
|
|
597
|
+
}),
|
|
577
598
|
value,
|
|
578
599
|
input.estimatedBridgeGas === void 0 ? void 0 : gasLimitWithBuffer(input.estimatedBridgeGas)
|
|
579
600
|
)
|
|
@@ -620,11 +641,15 @@ function buildSubtensorToEvmPlan(input) {
|
|
|
620
641
|
subtensor.chainId,
|
|
621
642
|
sender,
|
|
622
643
|
subtensor.contracts.stakingPrecompile,
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
644
|
+
encodeFunctionData({
|
|
645
|
+
abi: stakingAbi,
|
|
646
|
+
functionName: "approve",
|
|
647
|
+
args: [
|
|
648
|
+
subtensor.contracts.gateway,
|
|
649
|
+
input.netuid,
|
|
650
|
+
amountRao
|
|
651
|
+
]
|
|
652
|
+
}),
|
|
628
653
|
0n
|
|
629
654
|
)
|
|
630
655
|
);
|
|
@@ -646,14 +671,18 @@ function buildSubtensorToEvmPlan(input) {
|
|
|
646
671
|
subtensor.chainId,
|
|
647
672
|
sender,
|
|
648
673
|
subtensor.contracts.gateway,
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
674
|
+
encodeFunctionData({
|
|
675
|
+
abi: alphaAbi,
|
|
676
|
+
functionName: "bridgeOut",
|
|
677
|
+
args: [
|
|
678
|
+
evm.ccipSelector,
|
|
679
|
+
subtensor.contracts.wrappedTao,
|
|
680
|
+
recipient,
|
|
681
|
+
taoAmount,
|
|
682
|
+
stakedAlphaRao,
|
|
683
|
+
input.amountWei
|
|
684
|
+
]
|
|
685
|
+
}),
|
|
657
686
|
value,
|
|
658
687
|
input.estimatedBridgeGas === void 0 ? void 0 : gasLimitWithBuffer(input.estimatedBridgeGas)
|
|
659
688
|
)
|
|
@@ -679,29 +708,29 @@ async function prepareEvmToSubtensor(provider, input) {
|
|
|
679
708
|
wantLiquid: input.delivery === "liquid",
|
|
680
709
|
minTaoOut: input.amountWei
|
|
681
710
|
};
|
|
682
|
-
const token = new Contract(evm.contracts.wrappedTao, ERC20_ABI, provider);
|
|
683
|
-
const gateway = new Contract(
|
|
684
|
-
evm.contracts.gateway,
|
|
685
|
-
SPOKE_GATEWAY_ABI,
|
|
686
|
-
provider
|
|
687
|
-
);
|
|
688
711
|
const [allowanceWei, exactNetworkFeeWei] = await Promise.all([
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
712
|
+
provider.readContract({
|
|
713
|
+
address: evm.contracts.wrappedTao,
|
|
714
|
+
abi: erc20Abi,
|
|
715
|
+
functionName: "allowance",
|
|
716
|
+
args: [sender, evm.contracts.gateway]
|
|
717
|
+
}),
|
|
718
|
+
provider.readContract({
|
|
719
|
+
address: evm.contracts.gateway,
|
|
720
|
+
abi: spokeAbi,
|
|
721
|
+
functionName: "quoteBridgeToFinney",
|
|
722
|
+
args: [evm.contracts.wrappedTao, input.amountWei, exit]
|
|
723
|
+
})
|
|
696
724
|
]);
|
|
697
725
|
let estimatedBridgeGas;
|
|
698
726
|
if (allowanceWei >= input.amountWei) {
|
|
699
|
-
const data =
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
727
|
+
const data = encodeFunctionData({
|
|
728
|
+
abi: spokeAbi,
|
|
729
|
+
functionName: "bridgeToFinney",
|
|
730
|
+
args: [evm.contracts.wrappedTao, input.amountWei, exit]
|
|
731
|
+
});
|
|
703
732
|
estimatedBridgeGas = await provider.estimateGas({
|
|
704
|
-
|
|
733
|
+
account: sender,
|
|
705
734
|
to: evm.contracts.gateway,
|
|
706
735
|
data,
|
|
707
736
|
value: feeWithBuffer(exactNetworkFeeWei)
|
|
@@ -729,17 +758,17 @@ async function prepareSubtensorToEvm(provider, input) {
|
|
|
729
758
|
assertWholeRao(input.amountWei);
|
|
730
759
|
const { subtensor } = foreverMoneyDeployment;
|
|
731
760
|
const evm = getForeverMoneyEvmDeployment(input.evmChain);
|
|
732
|
-
const
|
|
733
|
-
subtensor.contracts.gateway,
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
);
|
|
761
|
+
const exactNetworkFeeWei = await provider.readContract({
|
|
762
|
+
address: subtensor.contracts.gateway,
|
|
763
|
+
abi: alphaAbi,
|
|
764
|
+
functionName: "quoteBridgeOut",
|
|
765
|
+
args: [
|
|
766
|
+
evm.ccipSelector,
|
|
767
|
+
subtensor.contracts.wrappedTao,
|
|
768
|
+
recipient,
|
|
769
|
+
input.amountWei
|
|
770
|
+
]
|
|
771
|
+
});
|
|
743
772
|
let stakingAllowanceRao;
|
|
744
773
|
if (input.source === "staked") {
|
|
745
774
|
if (input.netuid === void 0) {
|
|
@@ -749,16 +778,12 @@ async function prepareSubtensorToEvm(provider, input) {
|
|
|
749
778
|
);
|
|
750
779
|
}
|
|
751
780
|
assertNonNegativeAmount(input.netuid, "netuid");
|
|
752
|
-
|
|
753
|
-
subtensor.contracts.stakingPrecompile,
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
sender,
|
|
759
|
-
subtensor.contracts.gateway,
|
|
760
|
-
input.netuid
|
|
761
|
-
);
|
|
781
|
+
stakingAllowanceRao = await provider.readContract({
|
|
782
|
+
address: subtensor.contracts.stakingPrecompile,
|
|
783
|
+
abi: stakingAbi,
|
|
784
|
+
functionName: "allowance",
|
|
785
|
+
args: [sender, subtensor.contracts.gateway, input.netuid]
|
|
786
|
+
});
|
|
762
787
|
}
|
|
763
788
|
const taoAmount = input.source === "liquid" ? input.amountWei : 0n;
|
|
764
789
|
const stakedAlphaRao = input.source === "staked" ? input.amountWei / EVM_WEI_PER_RAO : 0n;
|
|
@@ -767,16 +792,20 @@ async function prepareSubtensorToEvm(provider, input) {
|
|
|
767
792
|
let estimatedBridgeGas;
|
|
768
793
|
if (input.source === "liquid" || stakingAllowanceRao !== void 0 && stakingAllowanceRao >= stakedAlphaRao) {
|
|
769
794
|
estimatedBridgeGas = await provider.estimateGas({
|
|
770
|
-
|
|
795
|
+
account: sender,
|
|
771
796
|
to: subtensor.contracts.gateway,
|
|
772
|
-
data:
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
797
|
+
data: encodeFunctionData({
|
|
798
|
+
abi: alphaAbi,
|
|
799
|
+
functionName: "bridgeOut",
|
|
800
|
+
args: [
|
|
801
|
+
evm.ccipSelector,
|
|
802
|
+
subtensor.contracts.wrappedTao,
|
|
803
|
+
recipient,
|
|
804
|
+
taoAmount,
|
|
805
|
+
stakedAlphaRao,
|
|
806
|
+
input.amountWei
|
|
807
|
+
]
|
|
808
|
+
}),
|
|
780
809
|
value
|
|
781
810
|
});
|
|
782
811
|
}
|
|
@@ -797,7 +826,7 @@ function prepareSubtensorToBase(provider, input) {
|
|
|
797
826
|
}
|
|
798
827
|
|
|
799
828
|
// src/core/transport.ts
|
|
800
|
-
import {
|
|
829
|
+
import { createPublicClient, custom } from "viem";
|
|
801
830
|
function isRecord(value) {
|
|
802
831
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
803
832
|
}
|
|
@@ -916,10 +945,42 @@ function providerFromTransport(transport) {
|
|
|
916
945
|
"An EIP-1193-compatible RPC transport is required."
|
|
917
946
|
);
|
|
918
947
|
}
|
|
919
|
-
return
|
|
948
|
+
return createPublicClient({
|
|
949
|
+
transport: custom(transport, { retryCount: 0 }),
|
|
950
|
+
cacheTime: 0,
|
|
951
|
+
batch: { multicall: false }
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
function trackingClient(provider) {
|
|
955
|
+
if (provider && "getChainId" in provider && typeof provider.getChainId === "function")
|
|
956
|
+
return provider;
|
|
957
|
+
if (provider && "send" in provider && typeof provider.send === "function") {
|
|
958
|
+
return providerFromTransport({
|
|
959
|
+
request: ({ method, params }) => {
|
|
960
|
+
if (params !== void 0 && !Array.isArray(params))
|
|
961
|
+
throw new ForeverMoneyError(
|
|
962
|
+
"RPC_ERROR",
|
|
963
|
+
"Tracking RPC params must be an array."
|
|
964
|
+
);
|
|
965
|
+
return provider.send(
|
|
966
|
+
method,
|
|
967
|
+
params === void 0 ? [] : [...params]
|
|
968
|
+
);
|
|
969
|
+
}
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
throw new ForeverMoneyError(
|
|
973
|
+
"MISSING_TRANSPORT",
|
|
974
|
+
"A viem public client or JSON-RPC provider is required."
|
|
975
|
+
);
|
|
920
976
|
}
|
|
921
977
|
|
|
922
978
|
// src/core/provider-errors.ts
|
|
979
|
+
import {
|
|
980
|
+
BaseError,
|
|
981
|
+
ContractFunctionRevertedError,
|
|
982
|
+
ExecutionRevertedError
|
|
983
|
+
} from "viem";
|
|
923
984
|
function stringProperty(value, property) {
|
|
924
985
|
if (typeof value !== "object" || value === null || !(property in value)) {
|
|
925
986
|
return void 0;
|
|
@@ -932,9 +993,13 @@ async function providerOperation(operation, action) {
|
|
|
932
993
|
return await action();
|
|
933
994
|
} catch (error) {
|
|
934
995
|
if (error instanceof ForeverMoneyError) throw error;
|
|
935
|
-
const
|
|
936
|
-
|
|
937
|
-
|
|
996
|
+
const revert = error instanceof BaseError ? error.walk(
|
|
997
|
+
(cause) => cause instanceof ContractFunctionRevertedError || cause instanceof ExecutionRevertedError
|
|
998
|
+
) : void 0;
|
|
999
|
+
const viemRevert = revert instanceof ContractFunctionRevertedError || revert instanceof ExecutionRevertedError;
|
|
1000
|
+
const causeCode = viemRevert ? revert.name : stringProperty(error, "code");
|
|
1001
|
+
const reason = viemRevert ? revert instanceof ContractFunctionRevertedError ? revert.data?.errorName ?? revert.reason : void 0 : stringProperty(error, "reason");
|
|
1002
|
+
const reverted = viemRevert || causeCode === "CALL_EXCEPTION";
|
|
938
1003
|
throw new ForeverMoneyError(
|
|
939
1004
|
reverted ? "SIMULATION_REVERTED" : "RPC_ERROR",
|
|
940
1005
|
reverted ? `${operation} reverted.` : `${operation} failed.`,
|
|
@@ -947,10 +1012,14 @@ async function providerOperation(operation, action) {
|
|
|
947
1012
|
}
|
|
948
1013
|
|
|
949
1014
|
// src/vaults/plans.ts
|
|
950
|
-
import {
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
1015
|
+
import {
|
|
1016
|
+
encodeFunctionData as encodeFunctionData2,
|
|
1017
|
+
parseAbi as parseAbi2,
|
|
1018
|
+
zeroAddress as zeroAddress2
|
|
1019
|
+
} from "viem";
|
|
1020
|
+
var erc20Abi2 = parseAbi2(ERC20_ABI);
|
|
1021
|
+
var factoryAbi = parseAbi2(VAULT_FACTORY_ABI);
|
|
1022
|
+
var managerAbi = parseAbi2(VAULT_MANAGER_ABI);
|
|
954
1023
|
function step(kind, label, from, to, data, value = 0n) {
|
|
955
1024
|
return {
|
|
956
1025
|
kind,
|
|
@@ -1067,10 +1136,11 @@ function buildCreateVaultPlan(input) {
|
|
|
1067
1136
|
`Approve ${stash.token} for the vault factory`,
|
|
1068
1137
|
owner,
|
|
1069
1138
|
stash.token,
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1139
|
+
encodeFunctionData2({
|
|
1140
|
+
abi: erc20Abi2,
|
|
1141
|
+
functionName: "approve",
|
|
1142
|
+
args: [base.contracts.vaultFactory, stash.amount]
|
|
1143
|
+
})
|
|
1074
1144
|
)
|
|
1075
1145
|
);
|
|
1076
1146
|
}
|
|
@@ -1081,15 +1151,19 @@ function buildCreateVaultPlan(input) {
|
|
|
1081
1151
|
"Create ForeverMoney vault",
|
|
1082
1152
|
owner,
|
|
1083
1153
|
base.contracts.vaultFactory,
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1154
|
+
encodeFunctionData2({
|
|
1155
|
+
abi: factoryAbi,
|
|
1156
|
+
functionName: "create",
|
|
1157
|
+
args: [
|
|
1158
|
+
owner,
|
|
1159
|
+
associatedMiner,
|
|
1160
|
+
akAddress,
|
|
1161
|
+
poolManager,
|
|
1162
|
+
poolAddress,
|
|
1163
|
+
positionManagerImplementation,
|
|
1164
|
+
stashTokens
|
|
1165
|
+
]
|
|
1166
|
+
}),
|
|
1093
1167
|
value
|
|
1094
1168
|
)
|
|
1095
1169
|
);
|
|
@@ -1108,14 +1182,15 @@ async function prepareCreateVault(provider, input) {
|
|
|
1108
1182
|
const allowances = await Promise.all(
|
|
1109
1183
|
erc20Stash.map(async ({ token }) => ({
|
|
1110
1184
|
token,
|
|
1111
|
-
allowance: await
|
|
1112
|
-
token,
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1185
|
+
allowance: await provider.readContract({
|
|
1186
|
+
address: token,
|
|
1187
|
+
abi: erc20Abi2,
|
|
1188
|
+
functionName: "allowance",
|
|
1189
|
+
args: [
|
|
1190
|
+
owner,
|
|
1191
|
+
foreverMoneyDeployment.base.contracts.vaultFactory
|
|
1192
|
+
]
|
|
1193
|
+
})
|
|
1119
1194
|
}))
|
|
1120
1195
|
);
|
|
1121
1196
|
return buildCreateVaultPlan({ ...input, allowances });
|
|
@@ -1142,11 +1217,11 @@ function buildDepositVaultPlan(input) {
|
|
|
1142
1217
|
"Deposit native ETH into the vault as WETH",
|
|
1143
1218
|
owner,
|
|
1144
1219
|
manager,
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
deposit.amount
|
|
1149
|
-
|
|
1220
|
+
encodeFunctionData2({
|
|
1221
|
+
abi: managerAbi,
|
|
1222
|
+
functionName: "topUpAk",
|
|
1223
|
+
args: [akAddress, zeroAddress2, deposit.amount]
|
|
1224
|
+
}),
|
|
1150
1225
|
deposit.amount
|
|
1151
1226
|
)
|
|
1152
1227
|
);
|
|
@@ -1166,10 +1241,11 @@ function buildDepositVaultPlan(input) {
|
|
|
1166
1241
|
`Approve ${deposit.token} for the vault manager`,
|
|
1167
1242
|
owner,
|
|
1168
1243
|
deposit.token,
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1244
|
+
encodeFunctionData2({
|
|
1245
|
+
abi: erc20Abi2,
|
|
1246
|
+
functionName: "approve",
|
|
1247
|
+
args: [manager, deposit.amount]
|
|
1248
|
+
})
|
|
1173
1249
|
)
|
|
1174
1250
|
);
|
|
1175
1251
|
}
|
|
@@ -1179,11 +1255,11 @@ function buildDepositVaultPlan(input) {
|
|
|
1179
1255
|
`Deposit ${deposit.token} into the vault`,
|
|
1180
1256
|
owner,
|
|
1181
1257
|
manager,
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
deposit.amount
|
|
1186
|
-
|
|
1258
|
+
encodeFunctionData2({
|
|
1259
|
+
abi: managerAbi,
|
|
1260
|
+
functionName: "topUpAk",
|
|
1261
|
+
args: [akAddress, deposit.token, deposit.amount]
|
|
1262
|
+
})
|
|
1187
1263
|
)
|
|
1188
1264
|
);
|
|
1189
1265
|
}
|
|
@@ -1203,11 +1279,12 @@ async function prepareDepositVault(provider, input) {
|
|
|
1203
1279
|
const allowances = await Promise.all(
|
|
1204
1280
|
erc20Deposits.map(async ({ token }) => ({
|
|
1205
1281
|
token,
|
|
1206
|
-
allowance: await
|
|
1207
|
-
token,
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1282
|
+
allowance: await provider.readContract({
|
|
1283
|
+
address: token,
|
|
1284
|
+
abi: erc20Abi2,
|
|
1285
|
+
functionName: "allowance",
|
|
1286
|
+
args: [owner, manager]
|
|
1287
|
+
})
|
|
1211
1288
|
}))
|
|
1212
1289
|
);
|
|
1213
1290
|
return buildDepositVaultPlan({ ...input, allowances });
|
|
@@ -1238,16 +1315,17 @@ function buildWithdrawVaultPlan(input) {
|
|
|
1238
1315
|
"Withdraw assets from the vault",
|
|
1239
1316
|
owner,
|
|
1240
1317
|
manager,
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1318
|
+
encodeFunctionData2({
|
|
1319
|
+
abi: managerAbi,
|
|
1320
|
+
functionName: "withdrawFromAkAndPositions",
|
|
1321
|
+
args: [
|
|
1244
1322
|
akAddress,
|
|
1245
1323
|
input.amount0,
|
|
1246
1324
|
input.amount1,
|
|
1247
1325
|
input.decreaseTokenIds,
|
|
1248
1326
|
input.unwrapWeth
|
|
1249
1327
|
]
|
|
1250
|
-
)
|
|
1328
|
+
})
|
|
1251
1329
|
)
|
|
1252
1330
|
]
|
|
1253
1331
|
});
|
|
@@ -1265,9 +1343,11 @@ function buildClaimVaultFeesPlan(input) {
|
|
|
1265
1343
|
"Claim vault fees",
|
|
1266
1344
|
owner,
|
|
1267
1345
|
manager,
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1346
|
+
encodeFunctionData2({
|
|
1347
|
+
abi: managerAbi,
|
|
1348
|
+
functionName: "claimFees",
|
|
1349
|
+
args: [akAddress]
|
|
1350
|
+
})
|
|
1271
1351
|
)
|
|
1272
1352
|
]
|
|
1273
1353
|
});
|
|
@@ -1287,20 +1367,25 @@ function buildSetVaultStakingPlan(input) {
|
|
|
1287
1367
|
`${input.staking ? "Stake" : "Unstake"} the vault position`,
|
|
1288
1368
|
owner,
|
|
1289
1369
|
manager,
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1370
|
+
encodeFunctionData2({
|
|
1371
|
+
abi: managerAbi,
|
|
1372
|
+
functionName: action,
|
|
1373
|
+
args: [akAddress, "0x"]
|
|
1374
|
+
})
|
|
1294
1375
|
)
|
|
1295
1376
|
]
|
|
1296
1377
|
});
|
|
1297
1378
|
}
|
|
1298
1379
|
|
|
1299
1380
|
// src/bridge/tracking.ts
|
|
1300
|
-
import {
|
|
1381
|
+
import {
|
|
1382
|
+
decodeEventLog as decodeEventLog2,
|
|
1383
|
+
parseAbi as parseAbi4,
|
|
1384
|
+
TransactionReceiptNotFoundError
|
|
1385
|
+
} from "viem";
|
|
1301
1386
|
|
|
1302
1387
|
// src/bridge/receipts.ts
|
|
1303
|
-
import {
|
|
1388
|
+
import { decodeEventLog, isHex as isHex2, parseAbi as parseAbi3 } from "viem";
|
|
1304
1389
|
|
|
1305
1390
|
// src/core/receipts.ts
|
|
1306
1391
|
function isLogFrom(log, address) {
|
|
@@ -1308,8 +1393,8 @@ function isLogFrom(log, address) {
|
|
|
1308
1393
|
}
|
|
1309
1394
|
|
|
1310
1395
|
// src/bridge/receipts.ts
|
|
1311
|
-
var
|
|
1312
|
-
var
|
|
1396
|
+
var alphaGatewayAbi = parseAbi3(ALPHA_GATEWAY_ABI);
|
|
1397
|
+
var spokeGatewayAbi = parseAbi3(SPOKE_GATEWAY_ABI);
|
|
1313
1398
|
function assertBridgeDirection(value) {
|
|
1314
1399
|
if (value !== "base-to-subtensor" && value !== "robinhood-to-subtensor" && value !== "subtensor-to-base" && value !== "subtensor-to-robinhood") {
|
|
1315
1400
|
throw new ForeverMoneyError(
|
|
@@ -1332,20 +1417,21 @@ function bridgeMessageIdFromReceipt(direction, receipt) {
|
|
|
1332
1417
|
evmChainFromBridgeDirection(direction)
|
|
1333
1418
|
);
|
|
1334
1419
|
const evmToSubtensor = isEvmToSubtensorDirection(direction);
|
|
1335
|
-
const [address,
|
|
1420
|
+
const [address, contractAbi, eventName] = evmToSubtensor ? [evm.contracts.gateway, spokeGatewayAbi, "BridgedToFinney"] : [
|
|
1336
1421
|
foreverMoneyDeployment.subtensor.contracts.gateway,
|
|
1337
|
-
|
|
1422
|
+
alphaGatewayAbi,
|
|
1338
1423
|
"BridgedOut"
|
|
1339
1424
|
];
|
|
1340
1425
|
for (const log of receipt.logs) {
|
|
1341
1426
|
if (!isLogFrom(log, address)) continue;
|
|
1342
1427
|
try {
|
|
1343
|
-
const parsed =
|
|
1428
|
+
const parsed = decodeEventLog({
|
|
1429
|
+
abi: contractAbi,
|
|
1344
1430
|
data: log.data,
|
|
1345
1431
|
topics: [...log.topics]
|
|
1346
1432
|
});
|
|
1347
|
-
const messageId = parsed
|
|
1348
|
-
if (parsed
|
|
1433
|
+
const messageId = "messageId" in parsed.args ? parsed.args.messageId : void 0;
|
|
1434
|
+
if (parsed.eventName === eventName && typeof messageId === "string" && isHex2(messageId, { strict: true }) && messageId.length === 66 && (evmToSubtensor || "destChainSelector" in parsed.args && parsed.args.destChainSelector === evm.ccipSelector)) {
|
|
1349
1435
|
return messageId.toLowerCase();
|
|
1350
1436
|
}
|
|
1351
1437
|
} catch {
|
|
@@ -1355,8 +1441,8 @@ function bridgeMessageIdFromReceipt(direction, receipt) {
|
|
|
1355
1441
|
}
|
|
1356
1442
|
|
|
1357
1443
|
// src/bridge/tracking.ts
|
|
1358
|
-
var
|
|
1359
|
-
var
|
|
1444
|
+
var ccipExecutionAbi = parseAbi4(CCIP_EXECUTION_ABI);
|
|
1445
|
+
var alphaGatewayAbi2 = parseAbi4(ALPHA_GATEWAY_ABI);
|
|
1360
1446
|
function destinationChainId(direction) {
|
|
1361
1447
|
assertBridgeDirection(direction);
|
|
1362
1448
|
const evm = getForeverMoneyEvmDeployment(
|
|
@@ -1372,14 +1458,14 @@ function sourceChainId(direction) {
|
|
|
1372
1458
|
return isEvmToSubtensorDirection(direction) ? evm.chainId : foreverMoneyDeployment.subtensor.chainId;
|
|
1373
1459
|
}
|
|
1374
1460
|
async function assertProviderChain(provider, expectedChainId, label) {
|
|
1375
|
-
const
|
|
1376
|
-
if (
|
|
1461
|
+
const chainId = await provider.getChainId();
|
|
1462
|
+
if (chainId !== expectedChainId) {
|
|
1377
1463
|
throw new ForeverMoneyError(
|
|
1378
1464
|
"CHAIN_MISMATCH",
|
|
1379
|
-
`${label} transport reported chain ID ${
|
|
1465
|
+
`${label} transport reported chain ID ${chainId}; expected ${expectedChainId}.`,
|
|
1380
1466
|
{
|
|
1381
1467
|
expectedChainId,
|
|
1382
|
-
actualChainId:
|
|
1468
|
+
actualChainId: chainId.toString()
|
|
1383
1469
|
}
|
|
1384
1470
|
);
|
|
1385
1471
|
}
|
|
@@ -1390,13 +1476,14 @@ async function assertDestinationProvider(provider, direction) {
|
|
|
1390
1476
|
return expectedChainId;
|
|
1391
1477
|
}
|
|
1392
1478
|
async function getBridgeSourceStatus(provider, input) {
|
|
1479
|
+
const client = trackingClient(provider);
|
|
1393
1480
|
const expectedChainId = sourceChainId(input.direction);
|
|
1394
1481
|
const transactionHash = normalizeBytes32(
|
|
1395
1482
|
input.transactionHash,
|
|
1396
1483
|
"Transaction hash"
|
|
1397
1484
|
);
|
|
1398
|
-
await assertProviderChain(
|
|
1399
|
-
const receipt = await
|
|
1485
|
+
await assertProviderChain(client, expectedChainId, "Bridge source");
|
|
1486
|
+
const receipt = await receiptOrNull(client, transactionHash);
|
|
1400
1487
|
if (receipt === null) {
|
|
1401
1488
|
return Object.freeze({
|
|
1402
1489
|
direction: input.direction,
|
|
@@ -1406,7 +1493,7 @@ async function getBridgeSourceStatus(provider, input) {
|
|
|
1406
1493
|
messageId: null
|
|
1407
1494
|
});
|
|
1408
1495
|
}
|
|
1409
|
-
if (receipt.status ===
|
|
1496
|
+
if (receipt.status === "reverted") {
|
|
1410
1497
|
return Object.freeze({
|
|
1411
1498
|
direction: input.direction,
|
|
1412
1499
|
sourceChainId: expectedChainId,
|
|
@@ -1415,7 +1502,7 @@ async function getBridgeSourceStatus(provider, input) {
|
|
|
1415
1502
|
messageId: null
|
|
1416
1503
|
});
|
|
1417
1504
|
}
|
|
1418
|
-
if (receipt.status !==
|
|
1505
|
+
if (receipt.status !== "success") {
|
|
1419
1506
|
throw new ForeverMoneyError(
|
|
1420
1507
|
"INVALID_PROVIDER_RESPONSE",
|
|
1421
1508
|
"The bridge source receipt has an invalid status."
|
|
@@ -1437,8 +1524,10 @@ async function getBridgeSourceStatus(provider, input) {
|
|
|
1437
1524
|
});
|
|
1438
1525
|
}
|
|
1439
1526
|
async function getCcipDeliveryCheckpoint(provider, direction) {
|
|
1440
|
-
const
|
|
1441
|
-
const
|
|
1527
|
+
const client = trackingClient(provider);
|
|
1528
|
+
const expectedChainId = await assertDestinationProvider(client, direction);
|
|
1529
|
+
const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
|
|
1530
|
+
const fromBlock = Number(blockNumber);
|
|
1442
1531
|
if (!Number.isSafeInteger(fromBlock) || fromBlock < 0) {
|
|
1443
1532
|
throw new ForeverMoneyError(
|
|
1444
1533
|
"INVALID_PROVIDER_RESPONSE",
|
|
@@ -1452,6 +1541,7 @@ async function getCcipDeliveryCheckpoint(provider, direction) {
|
|
|
1452
1541
|
});
|
|
1453
1542
|
}
|
|
1454
1543
|
async function getCcipDeliveryStatus(provider, input) {
|
|
1544
|
+
const client = trackingClient(provider);
|
|
1455
1545
|
const expectedChainId = destinationChainId(input.direction);
|
|
1456
1546
|
const messageId = normalizeBytes32(input.messageId, "CCIP message ID");
|
|
1457
1547
|
if (!Number.isSafeInteger(input.fromBlock) || input.fromBlock < 0) {
|
|
@@ -1460,30 +1550,27 @@ async function getCcipDeliveryStatus(provider, input) {
|
|
|
1460
1550
|
"CCIP fromBlock must be a non-negative safe integer."
|
|
1461
1551
|
);
|
|
1462
1552
|
}
|
|
1463
|
-
await assertProviderChain(
|
|
1464
|
-
const event = ccipExecutionInterface.getEvent("ExecutionStateChanged");
|
|
1465
|
-
if (event === null) {
|
|
1466
|
-
throw new Error("CCIP execution event is missing from the SDK ABI.");
|
|
1467
|
-
}
|
|
1553
|
+
await assertProviderChain(client, expectedChainId, "Bridge destination");
|
|
1468
1554
|
const evmChain = evmChainFromBridgeDirection(input.direction);
|
|
1469
1555
|
const evm = getForeverMoneyEvmDeployment(evmChain);
|
|
1470
1556
|
const evmToSubtensor = isEvmToSubtensorDirection(input.direction);
|
|
1471
1557
|
const sourceSelector = evmToSubtensor ? evm.ccipSelector : foreverMoneyDeployment.subtensor.ccipSelector;
|
|
1472
1558
|
const offRamp = evmToSubtensor ? evmChain === "base" ? foreverMoneyDeployment.subtensor.contracts.ccipOffRampFromBase : foreverMoneyDeployment.subtensor.contracts.ccipOffRampFromRobinhood : evm.contracts.ccipOffRampFromSubtensor;
|
|
1473
|
-
const logs = await
|
|
1559
|
+
const logs = await client.getLogs({
|
|
1474
1560
|
address: offRamp,
|
|
1475
|
-
fromBlock: input.fromBlock,
|
|
1561
|
+
fromBlock: BigInt(input.fromBlock),
|
|
1476
1562
|
toBlock: "latest",
|
|
1477
|
-
|
|
1563
|
+
event: ccipExecutionAbi[0],
|
|
1564
|
+
args: { sourceChainSelector: sourceSelector, messageId },
|
|
1565
|
+
strict: true
|
|
1478
1566
|
});
|
|
1479
1567
|
const latest = logs.at(-1);
|
|
1480
1568
|
if (latest === void 0) return "waiting";
|
|
1481
|
-
const
|
|
1482
|
-
const state = Number(parsed?.args.state);
|
|
1569
|
+
const state = latest.args.state;
|
|
1483
1570
|
if (state === 3) return "failure";
|
|
1484
1571
|
if (state !== 2) return "waiting";
|
|
1485
1572
|
if (!evmToSubtensor) return "success";
|
|
1486
|
-
const receipt = await
|
|
1573
|
+
const receipt = await receiptOrNull(client, latest.transactionHash);
|
|
1487
1574
|
if (receipt === null) {
|
|
1488
1575
|
throw new ForeverMoneyError(
|
|
1489
1576
|
"INVALID_PROVIDER_RESPONSE",
|
|
@@ -1495,7 +1582,11 @@ async function getCcipDeliveryStatus(provider, input) {
|
|
|
1495
1582
|
continue;
|
|
1496
1583
|
}
|
|
1497
1584
|
try {
|
|
1498
|
-
if (
|
|
1585
|
+
if (decodeEventLog2({
|
|
1586
|
+
abi: alphaGatewayAbi2,
|
|
1587
|
+
data: log.data,
|
|
1588
|
+
topics: log.topics
|
|
1589
|
+
}).eventName === "Claimable") {
|
|
1499
1590
|
return "recovery";
|
|
1500
1591
|
}
|
|
1501
1592
|
} catch {
|
|
@@ -1503,20 +1594,28 @@ async function getCcipDeliveryStatus(provider, input) {
|
|
|
1503
1594
|
}
|
|
1504
1595
|
return "success";
|
|
1505
1596
|
}
|
|
1597
|
+
async function receiptOrNull(provider, hash) {
|
|
1598
|
+
try {
|
|
1599
|
+
return await provider.getTransactionReceipt({ hash });
|
|
1600
|
+
} catch (error) {
|
|
1601
|
+
if (error instanceof TransactionReceiptNotFoundError) return null;
|
|
1602
|
+
throw error;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1506
1605
|
|
|
1507
1606
|
// src/client.ts
|
|
1508
1607
|
async function assertProviderChain2(provider, expectedChainId, name) {
|
|
1509
|
-
const
|
|
1608
|
+
const chainId = await providerOperation(
|
|
1510
1609
|
`Reading the ${name} chain ID`,
|
|
1511
|
-
() => provider.
|
|
1610
|
+
() => provider.getChainId()
|
|
1512
1611
|
);
|
|
1513
|
-
if (
|
|
1612
|
+
if (chainId !== expectedChainId) {
|
|
1514
1613
|
throw new ForeverMoneyError(
|
|
1515
1614
|
"CHAIN_MISMATCH",
|
|
1516
|
-
`${name} transport reported chain ID ${
|
|
1615
|
+
`${name} transport reported chain ID ${chainId}; expected ${expectedChainId}.`,
|
|
1517
1616
|
{
|
|
1518
1617
|
expectedChainId,
|
|
1519
|
-
actualChainId:
|
|
1618
|
+
actualChainId: chainId.toString()
|
|
1520
1619
|
}
|
|
1521
1620
|
);
|
|
1522
1621
|
}
|
|
@@ -1648,19 +1747,20 @@ function createForeverMoneyClient(options) {
|
|
|
1648
1747
|
}
|
|
1649
1748
|
|
|
1650
1749
|
// src/vaults/receipts.ts
|
|
1651
|
-
import {
|
|
1652
|
-
var
|
|
1750
|
+
import { decodeEventLog as decodeEventLog3, parseAbi as parseAbi5 } from "viem";
|
|
1751
|
+
var vaultFactoryAbi = parseAbi5(VAULT_FACTORY_ABI);
|
|
1653
1752
|
function vaultManagerFromCreationReceipt(receipt) {
|
|
1654
1753
|
for (const log of receipt.logs) {
|
|
1655
1754
|
if (!isLogFrom(log, foreverMoneyDeployment.base.contracts.vaultFactory)) {
|
|
1656
1755
|
continue;
|
|
1657
1756
|
}
|
|
1658
1757
|
try {
|
|
1659
|
-
const parsed =
|
|
1758
|
+
const parsed = decodeEventLog3({
|
|
1759
|
+
abi: vaultFactoryAbi,
|
|
1660
1760
|
data: log.data,
|
|
1661
1761
|
topics: [...log.topics]
|
|
1662
1762
|
});
|
|
1663
|
-
if (parsed
|
|
1763
|
+
if (parsed.eventName === "SnLiquidityManagerCreated") {
|
|
1664
1764
|
return normalizeEvmAddress(String(parsed.args.manager));
|
|
1665
1765
|
}
|
|
1666
1766
|
} catch {
|
|
@@ -1670,7 +1770,10 @@ function vaultManagerFromCreationReceipt(receipt) {
|
|
|
1670
1770
|
}
|
|
1671
1771
|
|
|
1672
1772
|
// src/core/transactions.ts
|
|
1673
|
-
import {
|
|
1773
|
+
import {
|
|
1774
|
+
defineChain,
|
|
1775
|
+
maxUint256 as maxUint2563
|
|
1776
|
+
} from "viem";
|
|
1674
1777
|
function decimalQuantity(value, label) {
|
|
1675
1778
|
if (!/^(0|[1-9][0-9]*)$/.test(value)) {
|
|
1676
1779
|
throw new ForeverMoneyError(
|
|
@@ -1679,7 +1782,7 @@ function decimalQuantity(value, label) {
|
|
|
1679
1782
|
);
|
|
1680
1783
|
}
|
|
1681
1784
|
const quantity = BigInt(value);
|
|
1682
|
-
if (quantity >
|
|
1785
|
+
if (quantity > maxUint2563) {
|
|
1683
1786
|
throw new ForeverMoneyError(
|
|
1684
1787
|
"INVALID_TRANSACTION_PLAN",
|
|
1685
1788
|
`${label} exceeds uint256.`
|
|
@@ -1715,6 +1818,52 @@ function toEthersTransaction(transaction) {
|
|
|
1715
1818
|
}
|
|
1716
1819
|
});
|
|
1717
1820
|
}
|
|
1821
|
+
var transactionChains = new Map(
|
|
1822
|
+
[
|
|
1823
|
+
[BASE_CHAIN_ID, "Base", "Ether", "ETH"],
|
|
1824
|
+
[ROBINHOOD_CHAIN_ID, "Robinhood", "Ether", "ETH"],
|
|
1825
|
+
[SUBTENSOR_CHAIN_ID, "Subtensor", "TAO", "TAO"]
|
|
1826
|
+
].map(([id, name, currency, symbol]) => [
|
|
1827
|
+
id,
|
|
1828
|
+
Object.freeze(
|
|
1829
|
+
defineChain({
|
|
1830
|
+
id,
|
|
1831
|
+
name,
|
|
1832
|
+
nativeCurrency: Object.freeze({
|
|
1833
|
+
name: currency,
|
|
1834
|
+
symbol,
|
|
1835
|
+
decimals: 18
|
|
1836
|
+
}),
|
|
1837
|
+
// Chain identity only. The caller retains ownership of the wallet transport.
|
|
1838
|
+
rpcUrls: Object.freeze({
|
|
1839
|
+
default: Object.freeze({ http: Object.freeze([]) })
|
|
1840
|
+
})
|
|
1841
|
+
})
|
|
1842
|
+
)
|
|
1843
|
+
])
|
|
1844
|
+
);
|
|
1845
|
+
function toViemTransaction(transaction) {
|
|
1846
|
+
const chain = transactionChains.get(transaction.chainId);
|
|
1847
|
+
if (!chain)
|
|
1848
|
+
throw new ForeverMoneyError(
|
|
1849
|
+
"INVALID_TRANSACTION_PLAN",
|
|
1850
|
+
"Unsupported transaction chain."
|
|
1851
|
+
);
|
|
1852
|
+
return Object.freeze({
|
|
1853
|
+
chain,
|
|
1854
|
+
account: transaction.from,
|
|
1855
|
+
chainId: transaction.chainId,
|
|
1856
|
+
to: transaction.to,
|
|
1857
|
+
data: transaction.data,
|
|
1858
|
+
value: decimalQuantity(transaction.value, "Transaction value"),
|
|
1859
|
+
...transaction.gasLimit === void 0 ? {} : {
|
|
1860
|
+
gas: decimalQuantity(
|
|
1861
|
+
transaction.gasLimit,
|
|
1862
|
+
"Transaction gas limit"
|
|
1863
|
+
)
|
|
1864
|
+
}
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1718
1867
|
export {
|
|
1719
1868
|
BASE_CCIP_SELECTOR,
|
|
1720
1869
|
BASE_CHAIN_ID,
|
|
@@ -1765,6 +1914,7 @@ export {
|
|
|
1765
1914
|
ss58ToPublicKey,
|
|
1766
1915
|
toEip1193Transaction,
|
|
1767
1916
|
toEthersTransaction,
|
|
1917
|
+
toViemTransaction,
|
|
1768
1918
|
vaultManagerFromCreationReceipt
|
|
1769
1919
|
};
|
|
1770
1920
|
//# sourceMappingURL=index.js.map
|