@forevermoney/sdk 0.2.0 → 0.5.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 +61 -0
- package/README.md +119 -0
- package/dist/index.cjs +452 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +59 -6
- package/dist/index.d.ts +59 -6
- package/dist/index.js +452 -87
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -92,7 +92,8 @@ var ROBINHOOD_CCIP_SELECTOR = 6180753054346818345n;
|
|
|
92
92
|
var SUBTENSOR_CCIP_SELECTOR = 2135107236357186872n;
|
|
93
93
|
var RAO_PER_TAO = 1000000000n;
|
|
94
94
|
var EVM_WEI_PER_RAO = 1000000000n;
|
|
95
|
-
var
|
|
95
|
+
var SN80_NETUID = 80n;
|
|
96
|
+
var FOREVERMONEY_DEPLOYMENT_VERSION = "1.3.0";
|
|
96
97
|
var foreverMoneyDeployment = Object.freeze({
|
|
97
98
|
version: FOREVERMONEY_DEPLOYMENT_VERSION,
|
|
98
99
|
base: Object.freeze({
|
|
@@ -101,10 +102,18 @@ var foreverMoneyDeployment = Object.freeze({
|
|
|
101
102
|
chainId: BASE_CHAIN_ID,
|
|
102
103
|
ccipSelector: BASE_CCIP_SELECTOR,
|
|
103
104
|
contracts: Object.freeze({
|
|
104
|
-
gateway: getAddress2("
|
|
105
|
+
gateway: getAddress2("0x1da2415229b614C787e145D1D7346eb496319C52"),
|
|
106
|
+
// Retired gateways, oldest first; kept only to track transfers sent
|
|
107
|
+
// through them.
|
|
108
|
+
legacyGateways: [
|
|
109
|
+
getAddress2("0x5EF3d7D19e4b233a1A169DA0d5CB02ec6b160a2C")
|
|
110
|
+
],
|
|
105
111
|
wrappedTao: getAddress2(
|
|
106
112
|
"0xf3081494b87e8d5fb7960f066e931d1d0e6e3d67"
|
|
107
113
|
),
|
|
114
|
+
wrappedSn80: getAddress2(
|
|
115
|
+
"0x6f63d869011f95274498023b4abfc00b30c34378"
|
|
116
|
+
),
|
|
108
117
|
ccipRouter: getAddress2(
|
|
109
118
|
"0x881e3A65B4d4a04dD529061dd0071cf975F58bCD"
|
|
110
119
|
),
|
|
@@ -130,7 +139,10 @@ var foreverMoneyDeployment = Object.freeze({
|
|
|
130
139
|
chainId: ROBINHOOD_CHAIN_ID,
|
|
131
140
|
ccipSelector: ROBINHOOD_CCIP_SELECTOR,
|
|
132
141
|
contracts: Object.freeze({
|
|
133
|
-
gateway: getAddress2("
|
|
142
|
+
gateway: getAddress2("0xf27fdA637131E25B2A1b4865ED9597d881980c7E"),
|
|
143
|
+
legacyGateways: [
|
|
144
|
+
getAddress2("0x53Dcc4FE04193e489BE537F722F65317DB1E65d8")
|
|
145
|
+
],
|
|
134
146
|
wrappedTao: getAddress2(
|
|
135
147
|
"0xf3081494B87e8D5fb7960f066E931D1D0e6E3d67"
|
|
136
148
|
),
|
|
@@ -146,13 +158,23 @@ var foreverMoneyDeployment = Object.freeze({
|
|
|
146
158
|
chainId: SUBTENSOR_CHAIN_ID,
|
|
147
159
|
ccipSelector: SUBTENSOR_CCIP_SELECTOR,
|
|
148
160
|
contracts: Object.freeze({
|
|
149
|
-
|
|
161
|
+
// V5.1 AlphaGateway: multi-validator staked input (tao-bridge 485c898).
|
|
162
|
+
gateway: getAddress2("0xd5Fa238aa4177f6c1341491969d9cBeec94EEd69"),
|
|
163
|
+
// V4 and V5 hubs. The spokes still deliver to the V5 hub (their hub
|
|
164
|
+
// pointer is immutable), so it stays here for delivery tracking.
|
|
165
|
+
legacyGateways: [
|
|
166
|
+
getAddress2("0x998f20Fea90bF7792774dECc7f994716442B1705"),
|
|
167
|
+
getAddress2("0xcd0C6d98D0A126B1c113d15b4c28F38321437787")
|
|
168
|
+
],
|
|
150
169
|
alphaVault: getAddress2(
|
|
151
170
|
"0x11837459896D96F821a8D88eC93a3C8D152033D4"
|
|
152
171
|
),
|
|
153
172
|
wrappedTao: getAddress2(
|
|
154
173
|
"0xC5b6C1632d34901239396F5E1BDe54B342900256"
|
|
155
174
|
),
|
|
175
|
+
wrappedSn80: getAddress2(
|
|
176
|
+
"0xfD628dE75EF96f0A5C59659159C6cA81E0DC2222"
|
|
177
|
+
),
|
|
156
178
|
ccipRouter: getAddress2(
|
|
157
179
|
"0xD941fBEcD2b971d0F54b4C34286C95faB52B60B8"
|
|
158
180
|
),
|
|
@@ -333,23 +355,39 @@ var SPOKE_GATEWAY_ABI = Object.freeze([
|
|
|
333
355
|
"function ROUTER() view returns (address)",
|
|
334
356
|
"function BITTENSOR_SELECTOR() view returns (uint64)",
|
|
335
357
|
"function SUBTENSOR_GATEWAY() view returns (address)",
|
|
358
|
+
"function maxIntegratorFeeBps() view returns (uint16)",
|
|
359
|
+
"function bridgeFeeBps() view returns (uint16)",
|
|
336
360
|
"function quoteBridgeToFinney(address token,uint256 amount,(bytes32 ss58,address evmFallback,bool wantLiquid,uint256 minTaoOut) exit) view returns (uint256 fee)",
|
|
337
361
|
"function bridgeToFinney(address token,uint256 amount,(bytes32 ss58,address evmFallback,bool wantLiquid,uint256 minTaoOut) exit) payable returns (bytes32 messageId)",
|
|
362
|
+
"function quoteBridgeToFinneyWithFee(address token,uint256 amount,(bytes32 ss58,address evmFallback,bool wantLiquid,uint256 minTaoOut) exit,uint256 gasLimit,(address recipient,uint16 bps) integrator) view returns (uint256 fee,uint256 cut,uint256 amountCrossing)",
|
|
363
|
+
"function bridgeToFinneyWithFee(address token,uint256 amount,(bytes32 ss58,address evmFallback,bool wantLiquid,uint256 minTaoOut) exit,uint256 gasLimit,(address recipient,uint16 bps) integrator) payable returns (bytes32 messageId)",
|
|
338
364
|
"event BridgedToFinney(address indexed token,address indexed sender,bytes32 indexed ss58,uint256 amount,bytes32 messageId)"
|
|
339
365
|
]);
|
|
340
366
|
var ALPHA_GATEWAY_ABI = Object.freeze([
|
|
341
367
|
"function ROUTER() view returns (address)",
|
|
342
368
|
"function allowedLane(uint64 selector) view returns (bool)",
|
|
369
|
+
"function maxIntegratorFeeBps() view returns (uint16)",
|
|
370
|
+
"function bridgeFeeBps() view returns (uint16)",
|
|
371
|
+
"function integratorTaoTopUp(uint256 taoAmount,uint16 bps) pure returns (uint256)",
|
|
343
372
|
"function quoteBridgeOut(uint64 destSelector,address token,address recipient,uint256 mintedAmount) view returns (uint256 fee)",
|
|
344
373
|
"function bridgeOut(uint64 destSelector,address token,address recipient,uint256 taoAmount,uint256 stakedAlphaRao,uint256 minTokenOut) payable returns (bytes32 messageId)",
|
|
374
|
+
"function integratorCut(uint256 amount,uint16 bps) pure returns (uint256)",
|
|
375
|
+
"function quoteBridgeOutWithFee(uint64 destSelector,address token,address recipient,uint256 mintedAmount,uint256 taoAmount,uint256 stakedAlphaRao,(address recipient,uint16 bps) integrator) view returns (uint256 fee,uint256 nativeTopUp,uint256 alphaTopUp,uint256 amountCrossing)",
|
|
376
|
+
"function bridgeOutWithFee(uint64 destSelector,address token,address recipient,uint256 taoAmount,uint256 stakedAlphaRao,uint256 minTokenOut,(address recipient,uint16 bps) integrator) payable returns (bytes32 messageId)",
|
|
377
|
+
"function bridgeOutFromValidators(uint64 destSelector,address token,address recipient,uint256 taoAmount,(bytes32 validator,uint256 alphaRao)[] sources,uint256 minTokenOut) payable returns (bytes32 messageId)",
|
|
378
|
+
"function bridgeOutFromValidatorsWithFee(uint64 destSelector,address token,address recipient,uint256 taoAmount,(bytes32 validator,uint256 alphaRao)[] sources,uint256 minTokenOut,(address recipient,uint16 bps) integrator) payable returns (bytes32 messageId)",
|
|
379
|
+
"function minStakeRequired() view returns (uint256)",
|
|
380
|
+
"function MAX_STAKE_SOURCES() view returns (uint256)",
|
|
381
|
+
"function GATEWAY_COLDKEY() view returns (bytes32)",
|
|
345
382
|
"function claimLiquid(address token,uint256 minTaoOut,address to)",
|
|
346
383
|
"function claimNative(address to)",
|
|
347
384
|
"function claimStaked(address token,bytes32 destColdkey,address to)",
|
|
348
385
|
"function claimToken(address token,address to)",
|
|
349
386
|
"function claimableNative(address account) view returns (uint256)",
|
|
350
|
-
"function claimableToken(address
|
|
387
|
+
"function claimableToken(address token,address account) view returns (uint256)",
|
|
351
388
|
"event BridgedOut(uint64 destChainSelector,address indexed token,address indexed sender,address indexed recipient,uint256 minted,bytes32 messageId)",
|
|
352
389
|
"event Claimable(address indexed token,address indexed user,uint256 native,uint256 wsn)",
|
|
390
|
+
"event NotDelivered(uint64 indexed sourceChainSelector,address indexed token,uint256 amount,uint8 reason)",
|
|
353
391
|
"event DeliveredLiquid(address indexed token,bytes32 indexed ss58,uint256 taoOut)",
|
|
354
392
|
"event DeliveredStaked(address indexed token,bytes32 indexed ss58,uint256 alphaRao)"
|
|
355
393
|
]);
|
|
@@ -507,6 +545,112 @@ var alphaAbi = parseAbi(ALPHA_GATEWAY_ABI);
|
|
|
507
545
|
var stakingAbi = parseAbi(STAKING_ABI);
|
|
508
546
|
var MIN_LIQUID_EVM_TO_SUBTENSOR_WEI = 10000000000000000n;
|
|
509
547
|
var MIN_LIQUID_BASE_TO_SUBTENSOR_WEI = MIN_LIQUID_EVM_TO_SUBTENSOR_WEI;
|
|
548
|
+
var MIN_LIQUID_SUBTENSOR_TO_EVM_WEI = 2000000n * EVM_WEI_PER_RAO;
|
|
549
|
+
var MAX_PARTNER_FEE_BPS = 1e4;
|
|
550
|
+
var MAX_STAKE_PULLS = 16;
|
|
551
|
+
var NO_PARTNER_FEE = {
|
|
552
|
+
recipient: "0x0000000000000000000000000000000000000000",
|
|
553
|
+
bps: 0
|
|
554
|
+
};
|
|
555
|
+
function resolvePartnerFee(fee, gateway) {
|
|
556
|
+
if (fee === void 0) return NO_PARTNER_FEE;
|
|
557
|
+
if (typeof fee.bps !== "number" || !Number.isInteger(fee.bps) || fee.bps < 0 || fee.bps > MAX_PARTNER_FEE_BPS) {
|
|
558
|
+
throw new ForeverMoneyError(
|
|
559
|
+
"INVALID_PARTNER_FEE",
|
|
560
|
+
`Partner fee bps must be an integer between 0 and ${MAX_PARTNER_FEE_BPS}.`,
|
|
561
|
+
{ bps: fee.bps }
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
if (fee.bps === 0) return NO_PARTNER_FEE;
|
|
565
|
+
const recipient = normalizeEvmAddress(fee.recipient);
|
|
566
|
+
if (recipient === NO_PARTNER_FEE.recipient || recipient.toLowerCase() === gateway.toLowerCase()) {
|
|
567
|
+
throw new ForeverMoneyError(
|
|
568
|
+
"INVALID_PARTNER_FEE",
|
|
569
|
+
"Partner fee recipient must not be the zero address or the gateway.",
|
|
570
|
+
{ recipient }
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
return { recipient, bps: fee.bps };
|
|
574
|
+
}
|
|
575
|
+
function partnerFeeCut(amount, bps) {
|
|
576
|
+
return amount * BigInt(bps) / 10000n;
|
|
577
|
+
}
|
|
578
|
+
function partnerFeeTaoTopUp(taoAmount, bps) {
|
|
579
|
+
const raw = partnerFeeCut(taoAmount, bps);
|
|
580
|
+
if (raw === 0n) return 0n;
|
|
581
|
+
return (raw + EVM_WEI_PER_RAO - 1n) / EVM_WEI_PER_RAO * EVM_WEI_PER_RAO;
|
|
582
|
+
}
|
|
583
|
+
function assertPartnerFeeAllowed(fee, maxBps) {
|
|
584
|
+
if (fee.bps > maxBps) {
|
|
585
|
+
throw new ForeverMoneyError(
|
|
586
|
+
"INVALID_PARTNER_FEE",
|
|
587
|
+
`Partner fee of ${fee.bps} bps exceeds the gateway maximum of ${maxBps} bps.`,
|
|
588
|
+
{ bps: fee.bps, maxBps }
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
function bridgeAsset(evmChain, asset = "tao") {
|
|
593
|
+
if (asset !== "tao" && asset !== "sn80") {
|
|
594
|
+
throw new ForeverMoneyError(
|
|
595
|
+
"INVALID_TRANSACTION_PLAN",
|
|
596
|
+
'Asset must be "tao" or "sn80".'
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
if (asset === "sn80" && evmChain !== "base") {
|
|
600
|
+
throw new ForeverMoneyError(
|
|
601
|
+
"INVALID_TRANSACTION_PLAN",
|
|
602
|
+
"SN80 bridging is supported between Base and Subtensor."
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
const evm = getForeverMoneyEvmDeployment(evmChain);
|
|
606
|
+
return asset === "sn80" ? {
|
|
607
|
+
evmToken: foreverMoneyDeployment.base.contracts.wrappedSn80,
|
|
608
|
+
subtensorToken: foreverMoneyDeployment.subtensor.contracts.wrappedSn80,
|
|
609
|
+
label: "SN80",
|
|
610
|
+
wrappedLabel: "SN80"
|
|
611
|
+
} : {
|
|
612
|
+
evmToken: evm.contracts.wrappedTao,
|
|
613
|
+
subtensorToken: foreverMoneyDeployment.subtensor.contracts.wrappedTao,
|
|
614
|
+
label: "TAO",
|
|
615
|
+
wrappedLabel: "wrapped TAO"
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function assertAssetMode(asset, mode) {
|
|
619
|
+
if (asset === "sn80" && mode !== "staked") {
|
|
620
|
+
throw new ForeverMoneyError(
|
|
621
|
+
"INVALID_TRANSACTION_PLAN",
|
|
622
|
+
"SN80 bridging requires staked subnet 80 input or delivery; liquid TAO conversion is not supported."
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
function sourceNetuid(input) {
|
|
627
|
+
if (input.source !== "staked") return void 0;
|
|
628
|
+
const netuid = input.netuid ?? (input.asset === "sn80" ? SN80_NETUID : void 0);
|
|
629
|
+
if (netuid === void 0) {
|
|
630
|
+
throw new ForeverMoneyError(
|
|
631
|
+
"INVALID_TRANSACTION_PLAN",
|
|
632
|
+
"A netuid is required when bridging staked TAO."
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
assertNonNegativeAmount(netuid, "netuid");
|
|
636
|
+
if (input.asset === "sn80" && netuid !== SN80_NETUID) {
|
|
637
|
+
throw new ForeverMoneyError(
|
|
638
|
+
"INVALID_TRANSACTION_PLAN",
|
|
639
|
+
"SN80 staking approvals must use netuid 80."
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
return netuid;
|
|
643
|
+
}
|
|
644
|
+
function stakePullsFor(input, amountRao) {
|
|
645
|
+
if (input.stakePulls === void 0) return void 0;
|
|
646
|
+
if (input.source !== "staked") {
|
|
647
|
+
throw new ForeverMoneyError(
|
|
648
|
+
"INVALID_TRANSACTION_PLAN",
|
|
649
|
+
"Stake pulls are only valid for a staked source."
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
return resolveStakePulls(input.stakePulls, amountRao);
|
|
653
|
+
}
|
|
510
654
|
function assertDelivery(value) {
|
|
511
655
|
if (value !== "liquid" && value !== "staked") {
|
|
512
656
|
throw new ForeverMoneyError(
|
|
@@ -536,6 +680,19 @@ function assertBaseToSubtensorAmount(amountWei, delivery) {
|
|
|
536
680
|
);
|
|
537
681
|
}
|
|
538
682
|
}
|
|
683
|
+
function assertSubtensorToEvmAmount(amountWei, source) {
|
|
684
|
+
assertWholeRao(amountWei);
|
|
685
|
+
if (source === "liquid" && amountWei < MIN_LIQUID_SUBTENSOR_TO_EVM_WEI) {
|
|
686
|
+
throw new ForeverMoneyError(
|
|
687
|
+
"AMOUNT_BELOW_MINIMUM",
|
|
688
|
+
"Bridging liquid TAO from Subtensor requires at least 0.002 TAO.",
|
|
689
|
+
{
|
|
690
|
+
amountWei: amountWei.toString(),
|
|
691
|
+
minimumAmountWei: MIN_LIQUID_SUBTENSOR_TO_EVM_WEI.toString()
|
|
692
|
+
}
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
539
696
|
function transactionStep(kind, label, chainId, from, to, data, value, gasLimit) {
|
|
540
697
|
return {
|
|
541
698
|
kind,
|
|
@@ -550,9 +707,159 @@ function transactionStep(kind, label, chainId, from, to, data, value, gasLimit)
|
|
|
550
707
|
}
|
|
551
708
|
};
|
|
552
709
|
}
|
|
710
|
+
function partnerFeeSummary(charged, unit, fee) {
|
|
711
|
+
if (fee.bps === 0) return "";
|
|
712
|
+
return ` Partner fee: ${charged} wei of ${unit} (${fee.bps} bps) on top, paid to ${fee.recipient}.`;
|
|
713
|
+
}
|
|
714
|
+
function encodeSpokeBridge(token, amountWei, exit, fee) {
|
|
715
|
+
return fee.bps === 0 ? encodeFunctionData({
|
|
716
|
+
abi: spokeAbi,
|
|
717
|
+
functionName: "bridgeToFinney",
|
|
718
|
+
args: [token, amountWei, exit]
|
|
719
|
+
}) : encodeFunctionData({
|
|
720
|
+
abi: spokeAbi,
|
|
721
|
+
functionName: "bridgeToFinneyWithFee",
|
|
722
|
+
args: [token, amountWei, exit, 0n, fee]
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
function resolveStakePulls(pulls, amountRao) {
|
|
726
|
+
if (pulls.length === 0 || pulls.length > MAX_STAKE_PULLS) {
|
|
727
|
+
throw new ForeverMoneyError(
|
|
728
|
+
"INVALID_TRANSACTION_PLAN",
|
|
729
|
+
`Between 1 and ${MAX_STAKE_PULLS} stake pulls are required.`,
|
|
730
|
+
{ count: pulls.length }
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
const seen = /* @__PURE__ */ new Set();
|
|
734
|
+
let total = 0n;
|
|
735
|
+
const resolved = pulls.map((pull) => {
|
|
736
|
+
const validator = normalizeBytes32(pull.hotkey, "Stake pull hotkey");
|
|
737
|
+
if (validator === `0x${"0".repeat(64)}`) {
|
|
738
|
+
throw new ForeverMoneyError(
|
|
739
|
+
"INVALID_TRANSACTION_PLAN",
|
|
740
|
+
"Stake pull hotkey must not be zero."
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
const key = validator.toLowerCase();
|
|
744
|
+
if (seen.has(key)) {
|
|
745
|
+
throw new ForeverMoneyError(
|
|
746
|
+
"INVALID_TRANSACTION_PLAN",
|
|
747
|
+
"Stake pulls must not repeat a hotkey.",
|
|
748
|
+
{ hotkey: validator }
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
seen.add(key);
|
|
752
|
+
if (typeof pull.amountRao !== "bigint" || pull.amountRao <= 0n) {
|
|
753
|
+
throw new ForeverMoneyError(
|
|
754
|
+
"INVALID_TRANSACTION_PLAN",
|
|
755
|
+
"Each stake pull must take a positive amount of RAO.",
|
|
756
|
+
{ hotkey: validator }
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
total += pull.amountRao;
|
|
760
|
+
return { validator, alphaRao: pull.amountRao };
|
|
761
|
+
});
|
|
762
|
+
if (total !== amountRao) {
|
|
763
|
+
throw new ForeverMoneyError(
|
|
764
|
+
"INVALID_TRANSACTION_PLAN",
|
|
765
|
+
"Stake pulls must sum to the bridged amount.",
|
|
766
|
+
{ pulledRao: total.toString(), amountRao: amountRao.toString() }
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
return resolved;
|
|
770
|
+
}
|
|
771
|
+
function encodeHubBridge(destSelector, token, recipient, taoAmount, stakedAlphaRao, minTokenOut, fee, pulls) {
|
|
772
|
+
if (pulls !== void 0) {
|
|
773
|
+
const args2 = [
|
|
774
|
+
destSelector,
|
|
775
|
+
token,
|
|
776
|
+
recipient,
|
|
777
|
+
taoAmount,
|
|
778
|
+
pulls,
|
|
779
|
+
minTokenOut
|
|
780
|
+
];
|
|
781
|
+
return fee.bps === 0 ? encodeFunctionData({
|
|
782
|
+
abi: alphaAbi,
|
|
783
|
+
functionName: "bridgeOutFromValidators",
|
|
784
|
+
args: args2
|
|
785
|
+
}) : encodeFunctionData({
|
|
786
|
+
abi: alphaAbi,
|
|
787
|
+
functionName: "bridgeOutFromValidatorsWithFee",
|
|
788
|
+
args: [...args2, fee]
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
const args = [
|
|
792
|
+
destSelector,
|
|
793
|
+
token,
|
|
794
|
+
recipient,
|
|
795
|
+
taoAmount,
|
|
796
|
+
stakedAlphaRao,
|
|
797
|
+
minTokenOut
|
|
798
|
+
];
|
|
799
|
+
return fee.bps === 0 ? encodeFunctionData({
|
|
800
|
+
abi: alphaAbi,
|
|
801
|
+
functionName: "bridgeOut",
|
|
802
|
+
args
|
|
803
|
+
}) : encodeFunctionData({
|
|
804
|
+
abi: alphaAbi,
|
|
805
|
+
functionName: "bridgeOutWithFee",
|
|
806
|
+
args: [...args, fee]
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
async function quoteSpokeWithFee(provider, gateway, token, amountWei, exit, fee) {
|
|
810
|
+
const maxBps = await provider.readContract({
|
|
811
|
+
address: gateway,
|
|
812
|
+
abi: spokeAbi,
|
|
813
|
+
functionName: "maxIntegratorFeeBps"
|
|
814
|
+
});
|
|
815
|
+
assertPartnerFeeAllowed(fee, maxBps);
|
|
816
|
+
const [networkFee] = await provider.readContract({
|
|
817
|
+
address: gateway,
|
|
818
|
+
abi: spokeAbi,
|
|
819
|
+
functionName: "quoteBridgeToFinneyWithFee",
|
|
820
|
+
args: [token, amountWei, exit, 0n, fee]
|
|
821
|
+
});
|
|
822
|
+
return networkFee;
|
|
823
|
+
}
|
|
824
|
+
async function quoteHubWithFee(provider, gateway, destSelector, token, recipient, mintedAmount, taoAmount, stakedAlphaRao, fee) {
|
|
825
|
+
const maxBps = await provider.readContract({
|
|
826
|
+
address: gateway,
|
|
827
|
+
abi: alphaAbi,
|
|
828
|
+
functionName: "maxIntegratorFeeBps"
|
|
829
|
+
});
|
|
830
|
+
assertPartnerFeeAllowed(fee, maxBps);
|
|
831
|
+
const [networkFee, taoTopUp, alphaTopUpRao, crossing] = await provider.readContract({
|
|
832
|
+
address: gateway,
|
|
833
|
+
abi: alphaAbi,
|
|
834
|
+
functionName: "quoteBridgeOutWithFee",
|
|
835
|
+
args: [
|
|
836
|
+
destSelector,
|
|
837
|
+
token,
|
|
838
|
+
recipient,
|
|
839
|
+
mintedAmount,
|
|
840
|
+
taoAmount,
|
|
841
|
+
stakedAlphaRao,
|
|
842
|
+
fee
|
|
843
|
+
]
|
|
844
|
+
});
|
|
845
|
+
if (crossing !== mintedAmount || taoTopUp !== partnerFeeTaoTopUp(taoAmount, fee.bps) || alphaTopUpRao !== partnerFeeCut(stakedAlphaRao, fee.bps)) {
|
|
846
|
+
throw new ForeverMoneyError(
|
|
847
|
+
"INVALID_PROVIDER_RESPONSE",
|
|
848
|
+
"The gateway partner fee quote does not match the SDK fee calculation.",
|
|
849
|
+
{
|
|
850
|
+
crossing: crossing.toString(),
|
|
851
|
+
taoTopUp: taoTopUp.toString(),
|
|
852
|
+
alphaTopUpRao: alphaTopUpRao.toString()
|
|
853
|
+
}
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
return { networkFee, taoTopUp, alphaTopUpRao };
|
|
857
|
+
}
|
|
553
858
|
function buildEvmToSubtensorPlan(input) {
|
|
554
859
|
const sender = normalizeEvmAddress(input.sender);
|
|
860
|
+
const asset = bridgeAsset(input.evmChain, input.asset);
|
|
555
861
|
assertDelivery(input.delivery);
|
|
862
|
+
assertAssetMode(input.asset, input.delivery);
|
|
556
863
|
assertBaseToSubtensorAmount(input.amountWei, input.delivery);
|
|
557
864
|
assertNonNegativeAmount(input.allowanceWei, "Token allowance");
|
|
558
865
|
assertNonNegativeAmount(input.exactNetworkFeeWei, "Network fee");
|
|
@@ -564,19 +871,24 @@ function buildEvmToSubtensorPlan(input) {
|
|
|
564
871
|
minTaoOut: input.amountWei
|
|
565
872
|
};
|
|
566
873
|
const evm = getForeverMoneyEvmDeployment(input.evmChain);
|
|
874
|
+
const partnerFee = resolvePartnerFee(
|
|
875
|
+
input.partnerFee,
|
|
876
|
+
evm.contracts.gateway
|
|
877
|
+
);
|
|
878
|
+
const cut = partnerFeeCut(input.amountWei, partnerFee.bps);
|
|
567
879
|
const steps = [];
|
|
568
|
-
if (input.allowanceWei < input.amountWei) {
|
|
880
|
+
if (input.allowanceWei < input.amountWei + cut) {
|
|
569
881
|
steps.push(
|
|
570
882
|
transactionStep(
|
|
571
883
|
"approval",
|
|
572
|
-
|
|
884
|
+
`Approve ${asset.wrappedLabel} for the ForeverMoney gateway`,
|
|
573
885
|
evm.chainId,
|
|
574
886
|
sender,
|
|
575
|
-
|
|
887
|
+
asset.evmToken,
|
|
576
888
|
encodeFunctionData({
|
|
577
889
|
abi: erc20Abi,
|
|
578
890
|
functionName: "approve",
|
|
579
|
-
args: [evm.contracts.gateway, input.amountWei]
|
|
891
|
+
args: [evm.contracts.gateway, input.amountWei + cut]
|
|
580
892
|
}),
|
|
581
893
|
0n
|
|
582
894
|
)
|
|
@@ -586,22 +898,23 @@ function buildEvmToSubtensorPlan(input) {
|
|
|
586
898
|
steps.push(
|
|
587
899
|
transactionStep(
|
|
588
900
|
"transaction",
|
|
589
|
-
`Bridge
|
|
901
|
+
`Bridge ${asset.wrappedLabel} from ${evm.name} to Subtensor (${input.delivery})`,
|
|
590
902
|
evm.chainId,
|
|
591
903
|
sender,
|
|
592
904
|
evm.contracts.gateway,
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
905
|
+
encodeSpokeBridge(
|
|
906
|
+
asset.evmToken,
|
|
907
|
+
input.amountWei,
|
|
908
|
+
exit,
|
|
909
|
+
partnerFee
|
|
910
|
+
),
|
|
598
911
|
value,
|
|
599
912
|
input.estimatedBridgeGas === void 0 ? void 0 : gasLimitWithBuffer(input.estimatedBridgeGas)
|
|
600
913
|
)
|
|
601
914
|
);
|
|
602
915
|
return createTransactionPlan({
|
|
603
916
|
action: evm.key === "base" ? "bridge.base-to-subtensor" : "bridge.robinhood-to-subtensor",
|
|
604
|
-
summary: `Bridge ${input.amountWei} wei of
|
|
917
|
+
summary: `Bridge ${input.amountWei} wei of ${asset.wrappedLabel} from ${evm.name} to ${destination}.${partnerFeeSummary(cut, asset.wrappedLabel, partnerFee)}`,
|
|
605
918
|
steps
|
|
606
919
|
});
|
|
607
920
|
}
|
|
@@ -611,21 +924,23 @@ function buildBaseToSubtensorPlan(input) {
|
|
|
611
924
|
function buildSubtensorToEvmPlan(input) {
|
|
612
925
|
const sender = normalizeEvmAddress(input.sender);
|
|
613
926
|
const recipient = normalizeEvmAddress(input.recipient);
|
|
927
|
+
const asset = bridgeAsset(input.evmChain, input.asset);
|
|
614
928
|
assertSource(input.source);
|
|
615
|
-
|
|
929
|
+
assertAssetMode(input.asset, input.source);
|
|
930
|
+
const netuid = sourceNetuid(input);
|
|
931
|
+
assertSubtensorToEvmAmount(input.amountWei, input.source);
|
|
616
932
|
assertNonNegativeAmount(input.exactNetworkFeeWei, "Network fee");
|
|
617
933
|
const { subtensor } = foreverMoneyDeployment;
|
|
618
934
|
const evm = getForeverMoneyEvmDeployment(input.evmChain);
|
|
935
|
+
const partnerFee = resolvePartnerFee(
|
|
936
|
+
input.partnerFee,
|
|
937
|
+
subtensor.contracts.gateway
|
|
938
|
+
);
|
|
619
939
|
const amountRao = input.amountWei / EVM_WEI_PER_RAO;
|
|
940
|
+
const alphaTopUpRao = input.source === "staked" ? partnerFeeCut(amountRao, partnerFee.bps) : 0n;
|
|
941
|
+
const taoTopUp = input.source === "liquid" ? partnerFeeTaoTopUp(input.amountWei, partnerFee.bps) : 0n;
|
|
620
942
|
const steps = [];
|
|
621
943
|
if (input.source === "staked") {
|
|
622
|
-
if (input.netuid === void 0) {
|
|
623
|
-
throw new ForeverMoneyError(
|
|
624
|
-
"INVALID_TRANSACTION_PLAN",
|
|
625
|
-
"A netuid is required when bridging staked TAO."
|
|
626
|
-
);
|
|
627
|
-
}
|
|
628
|
-
assertNonNegativeAmount(input.netuid, "netuid");
|
|
629
944
|
if (input.stakingAllowanceRao === void 0) {
|
|
630
945
|
throw new ForeverMoneyError(
|
|
631
946
|
"INVALID_TRANSACTION_PLAN",
|
|
@@ -633,11 +948,11 @@ function buildSubtensorToEvmPlan(input) {
|
|
|
633
948
|
);
|
|
634
949
|
}
|
|
635
950
|
assertNonNegativeAmount(input.stakingAllowanceRao, "Staking allowance");
|
|
636
|
-
if (input.stakingAllowanceRao < amountRao) {
|
|
951
|
+
if (input.stakingAllowanceRao < amountRao + alphaTopUpRao) {
|
|
637
952
|
steps.push(
|
|
638
953
|
transactionStep(
|
|
639
954
|
"approval",
|
|
640
|
-
|
|
955
|
+
`Approve staked ${asset.label} for the ForeverMoney gateway`,
|
|
641
956
|
subtensor.chainId,
|
|
642
957
|
sender,
|
|
643
958
|
subtensor.contracts.stakingPrecompile,
|
|
@@ -646,8 +961,8 @@ function buildSubtensorToEvmPlan(input) {
|
|
|
646
961
|
functionName: "approve",
|
|
647
962
|
args: [
|
|
648
963
|
subtensor.contracts.gateway,
|
|
649
|
-
|
|
650
|
-
amountRao
|
|
964
|
+
netuid,
|
|
965
|
+
amountRao + alphaTopUpRao
|
|
651
966
|
]
|
|
652
967
|
}),
|
|
653
968
|
0n
|
|
@@ -662,34 +977,37 @@ function buildSubtensorToEvmPlan(input) {
|
|
|
662
977
|
}
|
|
663
978
|
const taoAmount = input.source === "liquid" ? input.amountWei : 0n;
|
|
664
979
|
const stakedAlphaRao = input.source === "staked" ? amountRao : 0n;
|
|
665
|
-
const
|
|
980
|
+
const pulls = stakePullsFor(input, amountRao);
|
|
981
|
+
const value = taoAmount + taoTopUp + feeWithBuffer(input.exactNetworkFeeWei);
|
|
666
982
|
assertNonNegativeAmount(value, "Transaction value");
|
|
667
983
|
steps.push(
|
|
668
984
|
transactionStep(
|
|
669
985
|
"transaction",
|
|
670
|
-
`Bridge ${input.source}
|
|
986
|
+
`Bridge ${input.source} ${asset.label} from Subtensor to ${evm.name}`,
|
|
671
987
|
subtensor.chainId,
|
|
672
988
|
sender,
|
|
673
989
|
subtensor.contracts.gateway,
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
]
|
|
685
|
-
}),
|
|
990
|
+
encodeHubBridge(
|
|
991
|
+
evm.ccipSelector,
|
|
992
|
+
asset.subtensorToken,
|
|
993
|
+
recipient,
|
|
994
|
+
taoAmount,
|
|
995
|
+
stakedAlphaRao,
|
|
996
|
+
input.amountWei,
|
|
997
|
+
partnerFee,
|
|
998
|
+
pulls
|
|
999
|
+
),
|
|
686
1000
|
value,
|
|
687
1001
|
input.estimatedBridgeGas === void 0 ? void 0 : gasLimitWithBuffer(input.estimatedBridgeGas)
|
|
688
1002
|
)
|
|
689
1003
|
);
|
|
690
1004
|
return createTransactionPlan({
|
|
691
1005
|
action: evm.key === "base" ? "bridge.subtensor-to-base" : "bridge.subtensor-to-robinhood",
|
|
692
|
-
summary: `Bridge ${input.amountWei} wei of ${input.source}
|
|
1006
|
+
summary: `Bridge ${input.amountWei} wei of ${input.source} ${asset.label} from Subtensor to ${recipient} on ${evm.name}.${partnerFeeSummary(
|
|
1007
|
+
input.source === "liquid" ? taoTopUp : alphaTopUpRao * EVM_WEI_PER_RAO,
|
|
1008
|
+
input.source === "liquid" ? "TAO" : `staked ${asset.label}`,
|
|
1009
|
+
partnerFee
|
|
1010
|
+
)}`,
|
|
693
1011
|
steps
|
|
694
1012
|
});
|
|
695
1013
|
}
|
|
@@ -698,7 +1016,9 @@ function buildSubtensorToBasePlan(input) {
|
|
|
698
1016
|
}
|
|
699
1017
|
async function prepareEvmToSubtensor(provider, input) {
|
|
700
1018
|
const sender = normalizeEvmAddress(input.sender);
|
|
1019
|
+
const asset = bridgeAsset(input.evmChain, input.asset);
|
|
701
1020
|
assertDelivery(input.delivery);
|
|
1021
|
+
assertAssetMode(input.asset, input.delivery);
|
|
702
1022
|
assertBaseToSubtensorAmount(input.amountWei, input.delivery);
|
|
703
1023
|
const destination = normalizeSS58(input.destination);
|
|
704
1024
|
const evm = getForeverMoneyEvmDeployment(input.evmChain);
|
|
@@ -708,27 +1028,40 @@ async function prepareEvmToSubtensor(provider, input) {
|
|
|
708
1028
|
wantLiquid: input.delivery === "liquid",
|
|
709
1029
|
minTaoOut: input.amountWei
|
|
710
1030
|
};
|
|
1031
|
+
const partnerFee = resolvePartnerFee(
|
|
1032
|
+
input.partnerFee,
|
|
1033
|
+
evm.contracts.gateway
|
|
1034
|
+
);
|
|
1035
|
+
const cut = partnerFeeCut(input.amountWei, partnerFee.bps);
|
|
711
1036
|
const [allowanceWei, exactNetworkFeeWei] = await Promise.all([
|
|
712
1037
|
provider.readContract({
|
|
713
|
-
address:
|
|
1038
|
+
address: asset.evmToken,
|
|
714
1039
|
abi: erc20Abi,
|
|
715
1040
|
functionName: "allowance",
|
|
716
1041
|
args: [sender, evm.contracts.gateway]
|
|
717
1042
|
}),
|
|
718
|
-
provider.readContract({
|
|
1043
|
+
partnerFee.bps === 0 ? provider.readContract({
|
|
719
1044
|
address: evm.contracts.gateway,
|
|
720
1045
|
abi: spokeAbi,
|
|
721
1046
|
functionName: "quoteBridgeToFinney",
|
|
722
|
-
args: [
|
|
723
|
-
})
|
|
1047
|
+
args: [asset.evmToken, input.amountWei, exit]
|
|
1048
|
+
}) : quoteSpokeWithFee(
|
|
1049
|
+
provider,
|
|
1050
|
+
evm.contracts.gateway,
|
|
1051
|
+
asset.evmToken,
|
|
1052
|
+
input.amountWei,
|
|
1053
|
+
exit,
|
|
1054
|
+
partnerFee
|
|
1055
|
+
)
|
|
724
1056
|
]);
|
|
725
1057
|
let estimatedBridgeGas;
|
|
726
|
-
if (allowanceWei >= input.amountWei) {
|
|
727
|
-
const data =
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
1058
|
+
if (allowanceWei >= input.amountWei + cut) {
|
|
1059
|
+
const data = encodeSpokeBridge(
|
|
1060
|
+
asset.evmToken,
|
|
1061
|
+
input.amountWei,
|
|
1062
|
+
exit,
|
|
1063
|
+
partnerFee
|
|
1064
|
+
);
|
|
732
1065
|
estimatedBridgeGas = await provider.estimateGas({
|
|
733
1066
|
account: sender,
|
|
734
1067
|
to: evm.contracts.gateway,
|
|
@@ -745,6 +1078,7 @@ async function prepareEvmToSubtensor(provider, input) {
|
|
|
745
1078
|
return Object.freeze({
|
|
746
1079
|
exactNetworkFeeWei,
|
|
747
1080
|
transactionValueWei: feeWithBuffer(exactNetworkFeeWei),
|
|
1081
|
+
partnerFeeWei: cut,
|
|
748
1082
|
plan
|
|
749
1083
|
});
|
|
750
1084
|
}
|
|
@@ -754,58 +1088,68 @@ function prepareBaseToSubtensor(provider, input) {
|
|
|
754
1088
|
async function prepareSubtensorToEvm(provider, input) {
|
|
755
1089
|
const sender = normalizeEvmAddress(input.sender);
|
|
756
1090
|
const recipient = normalizeEvmAddress(input.recipient);
|
|
1091
|
+
const asset = bridgeAsset(input.evmChain, input.asset);
|
|
757
1092
|
assertSource(input.source);
|
|
758
|
-
|
|
1093
|
+
assertAssetMode(input.asset, input.source);
|
|
1094
|
+
const netuid = sourceNetuid(input);
|
|
1095
|
+
assertSubtensorToEvmAmount(input.amountWei, input.source);
|
|
759
1096
|
const { subtensor } = foreverMoneyDeployment;
|
|
760
1097
|
const evm = getForeverMoneyEvmDeployment(input.evmChain);
|
|
761
|
-
const
|
|
1098
|
+
const partnerFee = resolvePartnerFee(
|
|
1099
|
+
input.partnerFee,
|
|
1100
|
+
subtensor.contracts.gateway
|
|
1101
|
+
);
|
|
1102
|
+
const taoAmount = input.source === "liquid" ? input.amountWei : 0n;
|
|
1103
|
+
const stakedAlphaRao = input.source === "staked" ? input.amountWei / EVM_WEI_PER_RAO : 0n;
|
|
1104
|
+
const exactNetworkFeeWei = partnerFee.bps === 0 ? await provider.readContract({
|
|
762
1105
|
address: subtensor.contracts.gateway,
|
|
763
1106
|
abi: alphaAbi,
|
|
764
1107
|
functionName: "quoteBridgeOut",
|
|
765
1108
|
args: [
|
|
766
1109
|
evm.ccipSelector,
|
|
767
|
-
|
|
1110
|
+
asset.subtensorToken,
|
|
768
1111
|
recipient,
|
|
769
1112
|
input.amountWei
|
|
770
1113
|
]
|
|
771
|
-
})
|
|
1114
|
+
}) : (await quoteHubWithFee(
|
|
1115
|
+
provider,
|
|
1116
|
+
subtensor.contracts.gateway,
|
|
1117
|
+
evm.ccipSelector,
|
|
1118
|
+
asset.subtensorToken,
|
|
1119
|
+
recipient,
|
|
1120
|
+
input.amountWei,
|
|
1121
|
+
taoAmount,
|
|
1122
|
+
stakedAlphaRao,
|
|
1123
|
+
partnerFee
|
|
1124
|
+
)).networkFee;
|
|
772
1125
|
let stakingAllowanceRao;
|
|
773
1126
|
if (input.source === "staked") {
|
|
774
|
-
if (input.netuid === void 0) {
|
|
775
|
-
throw new ForeverMoneyError(
|
|
776
|
-
"INVALID_TRANSACTION_PLAN",
|
|
777
|
-
"A netuid is required when bridging staked TAO."
|
|
778
|
-
);
|
|
779
|
-
}
|
|
780
|
-
assertNonNegativeAmount(input.netuid, "netuid");
|
|
781
1127
|
stakingAllowanceRao = await provider.readContract({
|
|
782
1128
|
address: subtensor.contracts.stakingPrecompile,
|
|
783
1129
|
abi: stakingAbi,
|
|
784
1130
|
functionName: "allowance",
|
|
785
|
-
args: [sender, subtensor.contracts.gateway,
|
|
1131
|
+
args: [sender, subtensor.contracts.gateway, netuid]
|
|
786
1132
|
});
|
|
787
1133
|
}
|
|
788
|
-
const
|
|
789
|
-
const
|
|
790
|
-
const value = taoAmount + feeWithBuffer(exactNetworkFeeWei);
|
|
1134
|
+
const alphaTopUpRao = partnerFeeCut(stakedAlphaRao, partnerFee.bps);
|
|
1135
|
+
const taoTopUp = partnerFeeTaoTopUp(taoAmount, partnerFee.bps);
|
|
1136
|
+
const value = taoAmount + taoTopUp + feeWithBuffer(exactNetworkFeeWei);
|
|
791
1137
|
assertNonNegativeAmount(value, "Transaction value");
|
|
792
1138
|
let estimatedBridgeGas;
|
|
793
|
-
if (input.source === "liquid" || stakingAllowanceRao !== void 0 && stakingAllowanceRao >= stakedAlphaRao) {
|
|
1139
|
+
if (input.source === "liquid" || stakingAllowanceRao !== void 0 && stakingAllowanceRao >= stakedAlphaRao + alphaTopUpRao) {
|
|
794
1140
|
estimatedBridgeGas = await provider.estimateGas({
|
|
795
1141
|
account: sender,
|
|
796
1142
|
to: subtensor.contracts.gateway,
|
|
797
|
-
data:
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
]
|
|
808
|
-
}),
|
|
1143
|
+
data: encodeHubBridge(
|
|
1144
|
+
evm.ccipSelector,
|
|
1145
|
+
asset.subtensorToken,
|
|
1146
|
+
recipient,
|
|
1147
|
+
taoAmount,
|
|
1148
|
+
stakedAlphaRao,
|
|
1149
|
+
input.amountWei,
|
|
1150
|
+
partnerFee,
|
|
1151
|
+
stakePullsFor(input, stakedAlphaRao)
|
|
1152
|
+
),
|
|
809
1153
|
value
|
|
810
1154
|
});
|
|
811
1155
|
}
|
|
@@ -818,6 +1162,7 @@ async function prepareSubtensorToEvm(provider, input) {
|
|
|
818
1162
|
return Object.freeze({
|
|
819
1163
|
exactNetworkFeeWei,
|
|
820
1164
|
transactionValueWei: value,
|
|
1165
|
+
partnerFeeWei: input.source === "liquid" ? taoTopUp : alphaTopUpRao * EVM_WEI_PER_RAO,
|
|
821
1166
|
plan
|
|
822
1167
|
});
|
|
823
1168
|
}
|
|
@@ -1417,13 +1762,20 @@ function bridgeMessageIdFromReceipt(direction, receipt) {
|
|
|
1417
1762
|
evmChainFromBridgeDirection(direction)
|
|
1418
1763
|
);
|
|
1419
1764
|
const evmToSubtensor = isEvmToSubtensorDirection(direction);
|
|
1420
|
-
const [
|
|
1421
|
-
|
|
1765
|
+
const [addresses, contractAbi, eventName] = evmToSubtensor ? [
|
|
1766
|
+
[...evm.contracts.legacyGateways, evm.contracts.gateway],
|
|
1767
|
+
spokeGatewayAbi,
|
|
1768
|
+
"BridgedToFinney"
|
|
1769
|
+
] : [
|
|
1770
|
+
[
|
|
1771
|
+
...foreverMoneyDeployment.subtensor.contracts.legacyGateways,
|
|
1772
|
+
foreverMoneyDeployment.subtensor.contracts.gateway
|
|
1773
|
+
],
|
|
1422
1774
|
alphaGatewayAbi,
|
|
1423
1775
|
"BridgedOut"
|
|
1424
1776
|
];
|
|
1425
1777
|
for (const log of receipt.logs) {
|
|
1426
|
-
if (!isLogFrom(log, address)) continue;
|
|
1778
|
+
if (!addresses.some((address) => isLogFrom(log, address))) continue;
|
|
1427
1779
|
try {
|
|
1428
1780
|
const parsed = decodeEventLog({
|
|
1429
1781
|
abi: contractAbi,
|
|
@@ -1577,16 +1929,23 @@ async function getCcipDeliveryStatus(provider, input) {
|
|
|
1577
1929
|
"The CCIP execution receipt is unavailable."
|
|
1578
1930
|
);
|
|
1579
1931
|
}
|
|
1932
|
+
const subtensorGateways = [
|
|
1933
|
+
...foreverMoneyDeployment.subtensor.contracts.legacyGateways,
|
|
1934
|
+
foreverMoneyDeployment.subtensor.contracts.gateway
|
|
1935
|
+
];
|
|
1580
1936
|
for (const log of receipt.logs) {
|
|
1581
|
-
if (
|
|
1937
|
+
if (!subtensorGateways.some(
|
|
1938
|
+
(gateway) => log.address.toLowerCase() === gateway.toLowerCase()
|
|
1939
|
+
)) {
|
|
1582
1940
|
continue;
|
|
1583
1941
|
}
|
|
1584
1942
|
try {
|
|
1585
|
-
|
|
1943
|
+
const { eventName } = decodeEventLog2({
|
|
1586
1944
|
abi: alphaGatewayAbi2,
|
|
1587
1945
|
data: log.data,
|
|
1588
1946
|
topics: log.topics
|
|
1589
|
-
})
|
|
1947
|
+
});
|
|
1948
|
+
if (eventName === "Claimable" || eventName === "NotDelivered") {
|
|
1590
1949
|
return "recovery";
|
|
1591
1950
|
}
|
|
1592
1951
|
} catch {
|
|
@@ -1872,12 +2231,16 @@ export {
|
|
|
1872
2231
|
FOREVERMONEY_DEPLOYMENT_VERSION,
|
|
1873
2232
|
ForeverMoneyError,
|
|
1874
2233
|
GAS_LIMIT_BUFFER_BPS,
|
|
2234
|
+
MAX_PARTNER_FEE_BPS,
|
|
2235
|
+
MAX_STAKE_PULLS,
|
|
1875
2236
|
MIN_LIQUID_BASE_TO_SUBTENSOR_WEI,
|
|
1876
2237
|
MIN_LIQUID_EVM_TO_SUBTENSOR_WEI,
|
|
2238
|
+
MIN_LIQUID_SUBTENSOR_TO_EVM_WEI,
|
|
1877
2239
|
NETWORK_FEE_BUFFER_BPS,
|
|
1878
2240
|
RAO_PER_TAO,
|
|
1879
2241
|
ROBINHOOD_CCIP_SELECTOR,
|
|
1880
2242
|
ROBINHOOD_CHAIN_ID,
|
|
2243
|
+
SN80_NETUID,
|
|
1881
2244
|
SUBTENSOR_CCIP_SELECTOR,
|
|
1882
2245
|
SUBTENSOR_CHAIN_ID,
|
|
1883
2246
|
assertWholeRao,
|
|
@@ -1910,6 +2273,8 @@ export {
|
|
|
1910
2273
|
normalizeEvmAddress,
|
|
1911
2274
|
normalizeSS58,
|
|
1912
2275
|
parseTaoAmount,
|
|
2276
|
+
partnerFeeCut,
|
|
2277
|
+
partnerFeeTaoTopUp,
|
|
1913
2278
|
sourceChainId,
|
|
1914
2279
|
ss58ToPublicKey,
|
|
1915
2280
|
toEip1193Transaction,
|