@forevermoney/sdk 0.1.0 → 0.4.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/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
- decodeAddress,
5
- encodeAddress,
6
- evmToAddress
7
- } from "@polkadot/util-crypto";
8
- import { ZeroAddress, getAddress, isAddress } from "ethers";
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
- if (!isAddress(value) || value === ZeroAddress) {
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(value);
39
+ return getAddress(candidate);
32
40
  }
33
41
  function evmToMirrorSS58(evmAddress) {
34
- return evmToAddress(normalizeEvmAddress(evmAddress), BITTENSOR_SS58_PREFIX);
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 (!value || isHex(value)) throw new Error("Raw hex is not SS58.");
39
- const publicKey = decodeAddress(value, false, BITTENSOR_SS58_PREFIX);
40
- if (publicKey.length !== 32) throw new Error("Invalid key length.");
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 encodeAddress(decodeBittensorAddress(value), BITTENSOR_SS58_PREFIX);
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 u8aToHex(decodeBittensorAddress(value));
79
+ return bytesToHex(decodeBittensorAddress(value));
62
80
  }
63
81
 
64
82
  // src/core/amounts.ts
65
- import { MaxUint256, formatUnits, parseUnits } from "ethers";
83
+ import { maxUint256, formatUnits, parseUnits } from "viem";
66
84
 
67
85
  // src/chains/deployment.ts
68
- import { getAddress as getAddress2 } from "ethers";
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;
@@ -74,7 +92,8 @@ var ROBINHOOD_CCIP_SELECTOR = 6180753054346818345n;
74
92
  var SUBTENSOR_CCIP_SELECTOR = 2135107236357186872n;
75
93
  var RAO_PER_TAO = 1000000000n;
76
94
  var EVM_WEI_PER_RAO = 1000000000n;
77
- var FOREVERMONEY_DEPLOYMENT_VERSION = "1.1.0";
95
+ var SN80_NETUID = 80n;
96
+ var FOREVERMONEY_DEPLOYMENT_VERSION = "1.2.0";
78
97
  var foreverMoneyDeployment = Object.freeze({
79
98
  version: FOREVERMONEY_DEPLOYMENT_VERSION,
80
99
  base: Object.freeze({
@@ -83,10 +102,16 @@ var foreverMoneyDeployment = Object.freeze({
83
102
  chainId: BASE_CHAIN_ID,
84
103
  ccipSelector: BASE_CCIP_SELECTOR,
85
104
  contracts: Object.freeze({
86
- gateway: getAddress2("0x5EF3d7D19e4b233a1A169DA0d5CB02ec6b160a2C"),
105
+ gateway: getAddress2("0x1da2415229b614C787e145D1D7346eb496319C52"),
106
+ legacyGateway: getAddress2(
107
+ "0x5EF3d7D19e4b233a1A169DA0d5CB02ec6b160a2C"
108
+ ),
87
109
  wrappedTao: getAddress2(
88
110
  "0xf3081494b87e8d5fb7960f066e931d1d0e6e3d67"
89
111
  ),
112
+ wrappedSn80: getAddress2(
113
+ "0x6f63d869011f95274498023b4abfc00b30c34378"
114
+ ),
90
115
  ccipRouter: getAddress2(
91
116
  "0x881e3A65B4d4a04dD529061dd0071cf975F58bCD"
92
117
  ),
@@ -112,7 +137,10 @@ var foreverMoneyDeployment = Object.freeze({
112
137
  chainId: ROBINHOOD_CHAIN_ID,
113
138
  ccipSelector: ROBINHOOD_CCIP_SELECTOR,
114
139
  contracts: Object.freeze({
115
- gateway: getAddress2("0x53Dcc4FE04193e489BE537F722F65317DB1E65d8"),
140
+ gateway: getAddress2("0xf27fdA637131E25B2A1b4865ED9597d881980c7E"),
141
+ legacyGateway: getAddress2(
142
+ "0x53Dcc4FE04193e489BE537F722F65317DB1E65d8"
143
+ ),
116
144
  wrappedTao: getAddress2(
117
145
  "0xf3081494B87e8D5fb7960f066E931D1D0e6E3d67"
118
146
  ),
@@ -128,13 +156,19 @@ var foreverMoneyDeployment = Object.freeze({
128
156
  chainId: SUBTENSOR_CHAIN_ID,
129
157
  ccipSelector: SUBTENSOR_CCIP_SELECTOR,
130
158
  contracts: Object.freeze({
131
- gateway: getAddress2("0x998f20Fea90bF7792774dECc7f994716442B1705"),
159
+ gateway: getAddress2("0xcd0C6d98D0A126B1c113d15b4c28F38321437787"),
160
+ legacyGateway: getAddress2(
161
+ "0x998f20Fea90bF7792774dECc7f994716442B1705"
162
+ ),
132
163
  alphaVault: getAddress2(
133
164
  "0x11837459896D96F821a8D88eC93a3C8D152033D4"
134
165
  ),
135
166
  wrappedTao: getAddress2(
136
167
  "0xC5b6C1632d34901239396F5E1BDe54B342900256"
137
168
  ),
169
+ wrappedSn80: getAddress2(
170
+ "0xfD628dE75EF96f0A5C59659159C6cA81E0DC2222"
171
+ ),
138
172
  ccipRouter: getAddress2(
139
173
  "0xD941fBEcD2b971d0F54b4C34286C95faB52B60B8"
140
174
  ),
@@ -203,7 +237,7 @@ function assertWholeRao(amountWei) {
203
237
  "The amount cannot be negative."
204
238
  );
205
239
  }
206
- if (amountWei > MaxUint256) {
240
+ if (amountWei > maxUint256) {
207
241
  throw new ForeverMoneyError(
208
242
  "INVALID_TRANSACTION_PLAN",
209
243
  "The amount exceeds uint256."
@@ -229,7 +263,7 @@ function formatTaoAmount(amountWei) {
229
263
  "A TAO amount cannot be negative."
230
264
  );
231
265
  }
232
- if (amountWei > MaxUint256) {
266
+ if (amountWei > maxUint256) {
233
267
  throw new ForeverMoneyError(
234
268
  "INVALID_TRANSACTION_PLAN",
235
269
  "The TAO amount exceeds uint256."
@@ -241,7 +275,8 @@ function formatTaoAmount(amountWei) {
241
275
  "TAO amounts must resolve to a whole RAO."
242
276
  );
243
277
  }
244
- return formatUnits(amountWei, 18);
278
+ const formatted = formatUnits(amountWei, 18);
279
+ return formatted.includes(".") ? formatted : `${formatted}.0`;
245
280
  }
246
281
  function mulDivCeil(value, numerator, denominator) {
247
282
  return (value * numerator + denominator - 1n) / denominator;
@@ -264,7 +299,7 @@ function feeWithBuffer(fee) {
264
299
  BASIS_POINTS + NETWORK_FEE_BUFFER_BPS,
265
300
  BASIS_POINTS
266
301
  );
267
- if (buffered > MaxUint256) {
302
+ if (buffered > maxUint256) {
268
303
  throw new ForeverMoneyError(
269
304
  "INVALID_TRANSACTION_PLAN",
270
305
  "The buffered network fee exceeds uint256."
@@ -290,7 +325,7 @@ function gasLimitWithBuffer(gasLimit) {
290
325
  BASIS_POINTS + GAS_LIMIT_BUFFER_BPS,
291
326
  BASIS_POINTS
292
327
  );
293
- if (buffered > MaxUint256) {
328
+ if (buffered > maxUint256) {
294
329
  throw new ForeverMoneyError(
295
330
  "INVALID_TRANSACTION_PLAN",
296
331
  "The buffered gas limit exceeds uint256."
@@ -314,23 +349,34 @@ var SPOKE_GATEWAY_ABI = Object.freeze([
314
349
  "function ROUTER() view returns (address)",
315
350
  "function BITTENSOR_SELECTOR() view returns (uint64)",
316
351
  "function SUBTENSOR_GATEWAY() view returns (address)",
352
+ "function maxIntegratorFeeBps() view returns (uint16)",
353
+ "function bridgeFeeBps() view returns (uint16)",
317
354
  "function quoteBridgeToFinney(address token,uint256 amount,(bytes32 ss58,address evmFallback,bool wantLiquid,uint256 minTaoOut) exit) view returns (uint256 fee)",
318
355
  "function bridgeToFinney(address token,uint256 amount,(bytes32 ss58,address evmFallback,bool wantLiquid,uint256 minTaoOut) exit) payable returns (bytes32 messageId)",
356
+ "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)",
357
+ "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)",
319
358
  "event BridgedToFinney(address indexed token,address indexed sender,bytes32 indexed ss58,uint256 amount,bytes32 messageId)"
320
359
  ]);
321
360
  var ALPHA_GATEWAY_ABI = Object.freeze([
322
361
  "function ROUTER() view returns (address)",
323
362
  "function allowedLane(uint64 selector) view returns (bool)",
363
+ "function maxIntegratorFeeBps() view returns (uint16)",
364
+ "function bridgeFeeBps() view returns (uint16)",
365
+ "function integratorTaoTopUp(uint256 taoAmount,uint16 bps) pure returns (uint256)",
324
366
  "function quoteBridgeOut(uint64 destSelector,address token,address recipient,uint256 mintedAmount) view returns (uint256 fee)",
325
367
  "function bridgeOut(uint64 destSelector,address token,address recipient,uint256 taoAmount,uint256 stakedAlphaRao,uint256 minTokenOut) payable returns (bytes32 messageId)",
368
+ "function integratorCut(uint256 amount,uint16 bps) pure returns (uint256)",
369
+ "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)",
370
+ "function bridgeOutWithFee(uint64 destSelector,address token,address recipient,uint256 taoAmount,uint256 stakedAlphaRao,uint256 minTokenOut,(address recipient,uint16 bps) integrator) payable returns (bytes32 messageId)",
326
371
  "function claimLiquid(address token,uint256 minTaoOut,address to)",
327
372
  "function claimNative(address to)",
328
373
  "function claimStaked(address token,bytes32 destColdkey,address to)",
329
374
  "function claimToken(address token,address to)",
330
375
  "function claimableNative(address account) view returns (uint256)",
331
- "function claimableToken(address account,address token) view returns (uint256)",
376
+ "function claimableToken(address token,address account) view returns (uint256)",
332
377
  "event BridgedOut(uint64 destChainSelector,address indexed token,address indexed sender,address indexed recipient,uint256 minted,bytes32 messageId)",
333
378
  "event Claimable(address indexed token,address indexed user,uint256 native,uint256 wsn)",
379
+ "event NotDelivered(uint64 indexed sourceChainSelector,address indexed token,uint256 amount,uint8 reason)",
334
380
  "event DeliveredLiquid(address indexed token,bytes32 indexed ss58,uint256 taoOut)",
335
381
  "event DeliveredStaked(address indexed token,bytes32 indexed ss58,uint256 alphaRao)"
336
382
  ]);
@@ -374,10 +420,10 @@ var foreverMoneyAbis = Object.freeze({
374
420
  });
375
421
 
376
422
  // src/bridge/plans.ts
377
- import { Contract, Interface } from "ethers";
423
+ import { encodeFunctionData, parseAbi } from "viem";
378
424
 
379
425
  // src/core/plans.ts
380
- import { keccak256, toUtf8Bytes } from "ethers";
426
+ import { keccak256, stringToBytes as stringToBytes2 } from "viem";
381
427
  function createTransactionPlan(plan) {
382
428
  const steps = plan.steps.map(
383
429
  (step2) => Object.freeze({
@@ -394,12 +440,12 @@ function createTransactionPlan(plan) {
394
440
  };
395
441
  return Object.freeze({
396
442
  ...versionedPlan,
397
- hash: keccak256(toUtf8Bytes(JSON.stringify(versionedPlan)))
443
+ hash: keccak256(stringToBytes2(JSON.stringify(versionedPlan)))
398
444
  });
399
445
  }
400
446
 
401
447
  // src/core/validation.ts
402
- import { MaxUint256 as MaxUint2562, ZeroHash, isHexString } from "ethers";
448
+ import { maxUint256 as maxUint2562, zeroHash, isHex } from "viem";
403
449
  function assertBigInt(amount, label) {
404
450
  if (typeof amount !== "bigint") {
405
451
  throw new ForeverMoneyError(
@@ -422,7 +468,7 @@ function assertPositiveAmount(amount, label) {
422
468
  `${label} cannot be negative.`
423
469
  );
424
470
  }
425
- if (amount > MaxUint2562) {
471
+ if (amount > maxUint2562) {
426
472
  throw new ForeverMoneyError(
427
473
  "INVALID_TRANSACTION_PLAN",
428
474
  `${label} exceeds uint256.`
@@ -437,7 +483,7 @@ function assertNonNegativeAmount(amount, label) {
437
483
  `${label} cannot be negative.`
438
484
  );
439
485
  }
440
- if (amount > MaxUint2562) {
486
+ if (amount > maxUint2562) {
441
487
  throw new ForeverMoneyError(
442
488
  "INVALID_TRANSACTION_PLAN",
443
489
  `${label} exceeds uint256.`
@@ -469,7 +515,7 @@ function assertRecord(value, label) {
469
515
  }
470
516
  }
471
517
  function normalizeBytes32(value, label) {
472
- if (!isHexString(value, 32)) {
518
+ if (!isHex(value, { strict: true }) || value.length !== 66) {
473
519
  throw new ForeverMoneyError(
474
520
  "INVALID_BYTES32",
475
521
  `${label} must be a 32-byte hex value.`
@@ -478,16 +524,111 @@ function normalizeBytes32(value, label) {
478
524
  return value.toLowerCase();
479
525
  }
480
526
  function normalizeOptionalBytes32(value, label) {
481
- return value === void 0 ? ZeroHash : normalizeBytes32(value, label);
527
+ return value === void 0 ? zeroHash : normalizeBytes32(value, label);
482
528
  }
483
529
 
484
530
  // src/bridge/plans.ts
485
- var erc20Interface = new Interface(ERC20_ABI);
486
- var spokeInterface = new Interface(SPOKE_GATEWAY_ABI);
487
- var alphaInterface = new Interface(ALPHA_GATEWAY_ABI);
488
- var stakingInterface = new Interface(STAKING_ABI);
531
+ var erc20Abi = parseAbi(ERC20_ABI);
532
+ var spokeAbi = parseAbi(SPOKE_GATEWAY_ABI);
533
+ var alphaAbi = parseAbi(ALPHA_GATEWAY_ABI);
534
+ var stakingAbi = parseAbi(STAKING_ABI);
489
535
  var MIN_LIQUID_EVM_TO_SUBTENSOR_WEI = 10000000000000000n;
490
536
  var MIN_LIQUID_BASE_TO_SUBTENSOR_WEI = MIN_LIQUID_EVM_TO_SUBTENSOR_WEI;
537
+ var MIN_LIQUID_SUBTENSOR_TO_EVM_WEI = 2000000n * EVM_WEI_PER_RAO;
538
+ var MAX_PARTNER_FEE_BPS = 1e4;
539
+ var NO_PARTNER_FEE = {
540
+ recipient: "0x0000000000000000000000000000000000000000",
541
+ bps: 0
542
+ };
543
+ function resolvePartnerFee(fee, gateway) {
544
+ if (fee === void 0) return NO_PARTNER_FEE;
545
+ if (typeof fee.bps !== "number" || !Number.isInteger(fee.bps) || fee.bps < 0 || fee.bps > MAX_PARTNER_FEE_BPS) {
546
+ throw new ForeverMoneyError(
547
+ "INVALID_PARTNER_FEE",
548
+ `Partner fee bps must be an integer between 0 and ${MAX_PARTNER_FEE_BPS}.`,
549
+ { bps: fee.bps }
550
+ );
551
+ }
552
+ if (fee.bps === 0) return NO_PARTNER_FEE;
553
+ const recipient = normalizeEvmAddress(fee.recipient);
554
+ if (recipient === NO_PARTNER_FEE.recipient || recipient.toLowerCase() === gateway.toLowerCase()) {
555
+ throw new ForeverMoneyError(
556
+ "INVALID_PARTNER_FEE",
557
+ "Partner fee recipient must not be the zero address or the gateway.",
558
+ { recipient }
559
+ );
560
+ }
561
+ return { recipient, bps: fee.bps };
562
+ }
563
+ function partnerFeeCut(amount, bps) {
564
+ return amount * BigInt(bps) / 10000n;
565
+ }
566
+ function partnerFeeTaoTopUp(taoAmount, bps) {
567
+ const raw = partnerFeeCut(taoAmount, bps);
568
+ if (raw === 0n) return 0n;
569
+ return (raw + EVM_WEI_PER_RAO - 1n) / EVM_WEI_PER_RAO * EVM_WEI_PER_RAO;
570
+ }
571
+ function assertPartnerFeeAllowed(fee, maxBps) {
572
+ if (fee.bps > maxBps) {
573
+ throw new ForeverMoneyError(
574
+ "INVALID_PARTNER_FEE",
575
+ `Partner fee of ${fee.bps} bps exceeds the gateway maximum of ${maxBps} bps.`,
576
+ { bps: fee.bps, maxBps }
577
+ );
578
+ }
579
+ }
580
+ function bridgeAsset(evmChain, asset = "tao") {
581
+ if (asset !== "tao" && asset !== "sn80") {
582
+ throw new ForeverMoneyError(
583
+ "INVALID_TRANSACTION_PLAN",
584
+ 'Asset must be "tao" or "sn80".'
585
+ );
586
+ }
587
+ if (asset === "sn80" && evmChain !== "base") {
588
+ throw new ForeverMoneyError(
589
+ "INVALID_TRANSACTION_PLAN",
590
+ "SN80 bridging is supported between Base and Subtensor."
591
+ );
592
+ }
593
+ const evm = getForeverMoneyEvmDeployment(evmChain);
594
+ return asset === "sn80" ? {
595
+ evmToken: foreverMoneyDeployment.base.contracts.wrappedSn80,
596
+ subtensorToken: foreverMoneyDeployment.subtensor.contracts.wrappedSn80,
597
+ label: "SN80",
598
+ wrappedLabel: "SN80"
599
+ } : {
600
+ evmToken: evm.contracts.wrappedTao,
601
+ subtensorToken: foreverMoneyDeployment.subtensor.contracts.wrappedTao,
602
+ label: "TAO",
603
+ wrappedLabel: "wrapped TAO"
604
+ };
605
+ }
606
+ function assertAssetMode(asset, mode) {
607
+ if (asset === "sn80" && mode !== "staked") {
608
+ throw new ForeverMoneyError(
609
+ "INVALID_TRANSACTION_PLAN",
610
+ "SN80 bridging requires staked subnet 80 input or delivery; liquid TAO conversion is not supported."
611
+ );
612
+ }
613
+ }
614
+ function sourceNetuid(input) {
615
+ if (input.source !== "staked") return void 0;
616
+ const netuid = input.netuid ?? (input.asset === "sn80" ? SN80_NETUID : void 0);
617
+ if (netuid === void 0) {
618
+ throw new ForeverMoneyError(
619
+ "INVALID_TRANSACTION_PLAN",
620
+ "A netuid is required when bridging staked TAO."
621
+ );
622
+ }
623
+ assertNonNegativeAmount(netuid, "netuid");
624
+ if (input.asset === "sn80" && netuid !== SN80_NETUID) {
625
+ throw new ForeverMoneyError(
626
+ "INVALID_TRANSACTION_PLAN",
627
+ "SN80 staking approvals must use netuid 80."
628
+ );
629
+ }
630
+ return netuid;
631
+ }
491
632
  function assertDelivery(value) {
492
633
  if (value !== "liquid" && value !== "staked") {
493
634
  throw new ForeverMoneyError(
@@ -517,6 +658,19 @@ function assertBaseToSubtensorAmount(amountWei, delivery) {
517
658
  );
518
659
  }
519
660
  }
661
+ function assertSubtensorToEvmAmount(amountWei, source) {
662
+ assertWholeRao(amountWei);
663
+ if (source === "liquid" && amountWei < MIN_LIQUID_SUBTENSOR_TO_EVM_WEI) {
664
+ throw new ForeverMoneyError(
665
+ "AMOUNT_BELOW_MINIMUM",
666
+ "Bridging liquid TAO from Subtensor requires at least 0.002 TAO.",
667
+ {
668
+ amountWei: amountWei.toString(),
669
+ minimumAmountWei: MIN_LIQUID_SUBTENSOR_TO_EVM_WEI.toString()
670
+ }
671
+ );
672
+ }
673
+ }
520
674
  function transactionStep(kind, label, chainId, from, to, data, value, gasLimit) {
521
675
  return {
522
676
  kind,
@@ -531,9 +685,94 @@ function transactionStep(kind, label, chainId, from, to, data, value, gasLimit)
531
685
  }
532
686
  };
533
687
  }
688
+ function partnerFeeSummary(charged, unit, fee) {
689
+ if (fee.bps === 0) return "";
690
+ return ` Partner fee: ${charged} wei of ${unit} (${fee.bps} bps) on top, paid to ${fee.recipient}.`;
691
+ }
692
+ function encodeSpokeBridge(token, amountWei, exit, fee) {
693
+ return fee.bps === 0 ? encodeFunctionData({
694
+ abi: spokeAbi,
695
+ functionName: "bridgeToFinney",
696
+ args: [token, amountWei, exit]
697
+ }) : encodeFunctionData({
698
+ abi: spokeAbi,
699
+ functionName: "bridgeToFinneyWithFee",
700
+ args: [token, amountWei, exit, 0n, fee]
701
+ });
702
+ }
703
+ function encodeHubBridge(destSelector, token, recipient, taoAmount, stakedAlphaRao, minTokenOut, fee) {
704
+ const args = [
705
+ destSelector,
706
+ token,
707
+ recipient,
708
+ taoAmount,
709
+ stakedAlphaRao,
710
+ minTokenOut
711
+ ];
712
+ return fee.bps === 0 ? encodeFunctionData({
713
+ abi: alphaAbi,
714
+ functionName: "bridgeOut",
715
+ args
716
+ }) : encodeFunctionData({
717
+ abi: alphaAbi,
718
+ functionName: "bridgeOutWithFee",
719
+ args: [...args, fee]
720
+ });
721
+ }
722
+ async function quoteSpokeWithFee(provider, gateway, token, amountWei, exit, fee) {
723
+ const maxBps = await provider.readContract({
724
+ address: gateway,
725
+ abi: spokeAbi,
726
+ functionName: "maxIntegratorFeeBps"
727
+ });
728
+ assertPartnerFeeAllowed(fee, maxBps);
729
+ const [networkFee] = await provider.readContract({
730
+ address: gateway,
731
+ abi: spokeAbi,
732
+ functionName: "quoteBridgeToFinneyWithFee",
733
+ args: [token, amountWei, exit, 0n, fee]
734
+ });
735
+ return networkFee;
736
+ }
737
+ async function quoteHubWithFee(provider, gateway, destSelector, token, recipient, mintedAmount, taoAmount, stakedAlphaRao, fee) {
738
+ const maxBps = await provider.readContract({
739
+ address: gateway,
740
+ abi: alphaAbi,
741
+ functionName: "maxIntegratorFeeBps"
742
+ });
743
+ assertPartnerFeeAllowed(fee, maxBps);
744
+ const [networkFee, taoTopUp, alphaTopUpRao, crossing] = await provider.readContract({
745
+ address: gateway,
746
+ abi: alphaAbi,
747
+ functionName: "quoteBridgeOutWithFee",
748
+ args: [
749
+ destSelector,
750
+ token,
751
+ recipient,
752
+ mintedAmount,
753
+ taoAmount,
754
+ stakedAlphaRao,
755
+ fee
756
+ ]
757
+ });
758
+ if (crossing !== mintedAmount || taoTopUp !== partnerFeeTaoTopUp(taoAmount, fee.bps) || alphaTopUpRao !== partnerFeeCut(stakedAlphaRao, fee.bps)) {
759
+ throw new ForeverMoneyError(
760
+ "INVALID_PROVIDER_RESPONSE",
761
+ "The gateway partner fee quote does not match the SDK fee calculation.",
762
+ {
763
+ crossing: crossing.toString(),
764
+ taoTopUp: taoTopUp.toString(),
765
+ alphaTopUpRao: alphaTopUpRao.toString()
766
+ }
767
+ );
768
+ }
769
+ return { networkFee, taoTopUp, alphaTopUpRao };
770
+ }
534
771
  function buildEvmToSubtensorPlan(input) {
535
772
  const sender = normalizeEvmAddress(input.sender);
773
+ const asset = bridgeAsset(input.evmChain, input.asset);
536
774
  assertDelivery(input.delivery);
775
+ assertAssetMode(input.asset, input.delivery);
537
776
  assertBaseToSubtensorAmount(input.amountWei, input.delivery);
538
777
  assertNonNegativeAmount(input.allowanceWei, "Token allowance");
539
778
  assertNonNegativeAmount(input.exactNetworkFeeWei, "Network fee");
@@ -545,19 +784,25 @@ function buildEvmToSubtensorPlan(input) {
545
784
  minTaoOut: input.amountWei
546
785
  };
547
786
  const evm = getForeverMoneyEvmDeployment(input.evmChain);
787
+ const partnerFee = resolvePartnerFee(
788
+ input.partnerFee,
789
+ evm.contracts.gateway
790
+ );
791
+ const cut = partnerFeeCut(input.amountWei, partnerFee.bps);
548
792
  const steps = [];
549
- if (input.allowanceWei < input.amountWei) {
793
+ if (input.allowanceWei < input.amountWei + cut) {
550
794
  steps.push(
551
795
  transactionStep(
552
796
  "approval",
553
- "Approve wrapped TAO for the ForeverMoney gateway",
797
+ `Approve ${asset.wrappedLabel} for the ForeverMoney gateway`,
554
798
  evm.chainId,
555
799
  sender,
556
- evm.contracts.wrappedTao,
557
- erc20Interface.encodeFunctionData("approve", [
558
- evm.contracts.gateway,
559
- input.amountWei
560
- ]),
800
+ asset.evmToken,
801
+ encodeFunctionData({
802
+ abi: erc20Abi,
803
+ functionName: "approve",
804
+ args: [evm.contracts.gateway, input.amountWei + cut]
805
+ }),
561
806
  0n
562
807
  )
563
808
  );
@@ -566,13 +811,15 @@ function buildEvmToSubtensorPlan(input) {
566
811
  steps.push(
567
812
  transactionStep(
568
813
  "transaction",
569
- `Bridge wrapped TAO from ${evm.name} to Subtensor (${input.delivery})`,
814
+ `Bridge ${asset.wrappedLabel} from ${evm.name} to Subtensor (${input.delivery})`,
570
815
  evm.chainId,
571
816
  sender,
572
817
  evm.contracts.gateway,
573
- spokeInterface.encodeFunctionData(
574
- "bridgeToFinney(address,uint256,(bytes32,address,bool,uint256))",
575
- [evm.contracts.wrappedTao, input.amountWei, exit]
818
+ encodeSpokeBridge(
819
+ asset.evmToken,
820
+ input.amountWei,
821
+ exit,
822
+ partnerFee
576
823
  ),
577
824
  value,
578
825
  input.estimatedBridgeGas === void 0 ? void 0 : gasLimitWithBuffer(input.estimatedBridgeGas)
@@ -580,7 +827,7 @@ function buildEvmToSubtensorPlan(input) {
580
827
  );
581
828
  return createTransactionPlan({
582
829
  action: evm.key === "base" ? "bridge.base-to-subtensor" : "bridge.robinhood-to-subtensor",
583
- summary: `Bridge ${input.amountWei} wei of wrapped TAO from ${evm.name} to ${destination}.`,
830
+ summary: `Bridge ${input.amountWei} wei of ${asset.wrappedLabel} from ${evm.name} to ${destination}.${partnerFeeSummary(cut, asset.wrappedLabel, partnerFee)}`,
584
831
  steps
585
832
  });
586
833
  }
@@ -590,21 +837,23 @@ function buildBaseToSubtensorPlan(input) {
590
837
  function buildSubtensorToEvmPlan(input) {
591
838
  const sender = normalizeEvmAddress(input.sender);
592
839
  const recipient = normalizeEvmAddress(input.recipient);
840
+ const asset = bridgeAsset(input.evmChain, input.asset);
593
841
  assertSource(input.source);
594
- assertWholeRao(input.amountWei);
842
+ assertAssetMode(input.asset, input.source);
843
+ const netuid = sourceNetuid(input);
844
+ assertSubtensorToEvmAmount(input.amountWei, input.source);
595
845
  assertNonNegativeAmount(input.exactNetworkFeeWei, "Network fee");
596
846
  const { subtensor } = foreverMoneyDeployment;
597
847
  const evm = getForeverMoneyEvmDeployment(input.evmChain);
848
+ const partnerFee = resolvePartnerFee(
849
+ input.partnerFee,
850
+ subtensor.contracts.gateway
851
+ );
598
852
  const amountRao = input.amountWei / EVM_WEI_PER_RAO;
853
+ const alphaTopUpRao = input.source === "staked" ? partnerFeeCut(amountRao, partnerFee.bps) : 0n;
854
+ const taoTopUp = input.source === "liquid" ? partnerFeeTaoTopUp(input.amountWei, partnerFee.bps) : 0n;
599
855
  const steps = [];
600
856
  if (input.source === "staked") {
601
- if (input.netuid === void 0) {
602
- throw new ForeverMoneyError(
603
- "INVALID_TRANSACTION_PLAN",
604
- "A netuid is required when bridging staked TAO."
605
- );
606
- }
607
- assertNonNegativeAmount(input.netuid, "netuid");
608
857
  if (input.stakingAllowanceRao === void 0) {
609
858
  throw new ForeverMoneyError(
610
859
  "INVALID_TRANSACTION_PLAN",
@@ -612,19 +861,23 @@ function buildSubtensorToEvmPlan(input) {
612
861
  );
613
862
  }
614
863
  assertNonNegativeAmount(input.stakingAllowanceRao, "Staking allowance");
615
- if (input.stakingAllowanceRao < amountRao) {
864
+ if (input.stakingAllowanceRao < amountRao + alphaTopUpRao) {
616
865
  steps.push(
617
866
  transactionStep(
618
867
  "approval",
619
- "Approve staked TAO for the ForeverMoney gateway",
868
+ `Approve staked ${asset.label} for the ForeverMoney gateway`,
620
869
  subtensor.chainId,
621
870
  sender,
622
871
  subtensor.contracts.stakingPrecompile,
623
- stakingInterface.encodeFunctionData("approve", [
624
- subtensor.contracts.gateway,
625
- input.netuid,
626
- amountRao
627
- ]),
872
+ encodeFunctionData({
873
+ abi: stakingAbi,
874
+ functionName: "approve",
875
+ args: [
876
+ subtensor.contracts.gateway,
877
+ netuid,
878
+ amountRao + alphaTopUpRao
879
+ ]
880
+ }),
628
881
  0n
629
882
  )
630
883
  );
@@ -637,30 +890,35 @@ function buildSubtensorToEvmPlan(input) {
637
890
  }
638
891
  const taoAmount = input.source === "liquid" ? input.amountWei : 0n;
639
892
  const stakedAlphaRao = input.source === "staked" ? amountRao : 0n;
640
- const value = taoAmount + feeWithBuffer(input.exactNetworkFeeWei);
893
+ const value = taoAmount + taoTopUp + feeWithBuffer(input.exactNetworkFeeWei);
641
894
  assertNonNegativeAmount(value, "Transaction value");
642
895
  steps.push(
643
896
  transactionStep(
644
897
  "transaction",
645
- `Bridge ${input.source} TAO from Subtensor to ${evm.name}`,
898
+ `Bridge ${input.source} ${asset.label} from Subtensor to ${evm.name}`,
646
899
  subtensor.chainId,
647
900
  sender,
648
901
  subtensor.contracts.gateway,
649
- alphaInterface.encodeFunctionData("bridgeOut", [
902
+ encodeHubBridge(
650
903
  evm.ccipSelector,
651
- subtensor.contracts.wrappedTao,
904
+ asset.subtensorToken,
652
905
  recipient,
653
906
  taoAmount,
654
907
  stakedAlphaRao,
655
- input.amountWei
656
- ]),
908
+ input.amountWei,
909
+ partnerFee
910
+ ),
657
911
  value,
658
912
  input.estimatedBridgeGas === void 0 ? void 0 : gasLimitWithBuffer(input.estimatedBridgeGas)
659
913
  )
660
914
  );
661
915
  return createTransactionPlan({
662
916
  action: evm.key === "base" ? "bridge.subtensor-to-base" : "bridge.subtensor-to-robinhood",
663
- summary: `Bridge ${input.amountWei} wei of ${input.source} TAO from Subtensor to ${recipient} on ${evm.name}.`,
917
+ summary: `Bridge ${input.amountWei} wei of ${input.source} ${asset.label} from Subtensor to ${recipient} on ${evm.name}.${partnerFeeSummary(
918
+ input.source === "liquid" ? taoTopUp : alphaTopUpRao * EVM_WEI_PER_RAO,
919
+ input.source === "liquid" ? "TAO" : `staked ${asset.label}`,
920
+ partnerFee
921
+ )}`,
664
922
  steps
665
923
  });
666
924
  }
@@ -669,7 +927,9 @@ function buildSubtensorToBasePlan(input) {
669
927
  }
670
928
  async function prepareEvmToSubtensor(provider, input) {
671
929
  const sender = normalizeEvmAddress(input.sender);
930
+ const asset = bridgeAsset(input.evmChain, input.asset);
672
931
  assertDelivery(input.delivery);
932
+ assertAssetMode(input.asset, input.delivery);
673
933
  assertBaseToSubtensorAmount(input.amountWei, input.delivery);
674
934
  const destination = normalizeSS58(input.destination);
675
935
  const evm = getForeverMoneyEvmDeployment(input.evmChain);
@@ -679,29 +939,42 @@ async function prepareEvmToSubtensor(provider, input) {
679
939
  wantLiquid: input.delivery === "liquid",
680
940
  minTaoOut: input.amountWei
681
941
  };
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
942
+ const partnerFee = resolvePartnerFee(
943
+ input.partnerFee,
944
+ evm.contracts.gateway
687
945
  );
946
+ const cut = partnerFeeCut(input.amountWei, partnerFee.bps);
688
947
  const [allowanceWei, exactNetworkFeeWei] = await Promise.all([
689
- token.getFunction("allowance")(
690
- sender,
691
- evm.contracts.gateway
692
- ),
693
- gateway.getFunction(
694
- "quoteBridgeToFinney(address,uint256,(bytes32,address,bool,uint256))"
695
- )(evm.contracts.wrappedTao, input.amountWei, exit)
948
+ provider.readContract({
949
+ address: asset.evmToken,
950
+ abi: erc20Abi,
951
+ functionName: "allowance",
952
+ args: [sender, evm.contracts.gateway]
953
+ }),
954
+ partnerFee.bps === 0 ? provider.readContract({
955
+ address: evm.contracts.gateway,
956
+ abi: spokeAbi,
957
+ functionName: "quoteBridgeToFinney",
958
+ args: [asset.evmToken, input.amountWei, exit]
959
+ }) : quoteSpokeWithFee(
960
+ provider,
961
+ evm.contracts.gateway,
962
+ asset.evmToken,
963
+ input.amountWei,
964
+ exit,
965
+ partnerFee
966
+ )
696
967
  ]);
697
968
  let estimatedBridgeGas;
698
- if (allowanceWei >= input.amountWei) {
699
- const data = spokeInterface.encodeFunctionData(
700
- "bridgeToFinney(address,uint256,(bytes32,address,bool,uint256))",
701
- [evm.contracts.wrappedTao, input.amountWei, exit]
969
+ if (allowanceWei >= input.amountWei + cut) {
970
+ const data = encodeSpokeBridge(
971
+ asset.evmToken,
972
+ input.amountWei,
973
+ exit,
974
+ partnerFee
702
975
  );
703
976
  estimatedBridgeGas = await provider.estimateGas({
704
- from: sender,
977
+ account: sender,
705
978
  to: evm.contracts.gateway,
706
979
  data,
707
980
  value: feeWithBuffer(exactNetworkFeeWei)
@@ -716,6 +989,7 @@ async function prepareEvmToSubtensor(provider, input) {
716
989
  return Object.freeze({
717
990
  exactNetworkFeeWei,
718
991
  transactionValueWei: feeWithBuffer(exactNetworkFeeWei),
992
+ partnerFeeWei: cut,
719
993
  plan
720
994
  });
721
995
  }
@@ -725,58 +999,67 @@ function prepareBaseToSubtensor(provider, input) {
725
999
  async function prepareSubtensorToEvm(provider, input) {
726
1000
  const sender = normalizeEvmAddress(input.sender);
727
1001
  const recipient = normalizeEvmAddress(input.recipient);
1002
+ const asset = bridgeAsset(input.evmChain, input.asset);
728
1003
  assertSource(input.source);
729
- assertWholeRao(input.amountWei);
1004
+ assertAssetMode(input.asset, input.source);
1005
+ const netuid = sourceNetuid(input);
1006
+ assertSubtensorToEvmAmount(input.amountWei, input.source);
730
1007
  const { subtensor } = foreverMoneyDeployment;
731
1008
  const evm = getForeverMoneyEvmDeployment(input.evmChain);
732
- const gateway = new Contract(
733
- subtensor.contracts.gateway,
734
- ALPHA_GATEWAY_ABI,
735
- provider
1009
+ const partnerFee = resolvePartnerFee(
1010
+ input.partnerFee,
1011
+ subtensor.contracts.gateway
736
1012
  );
737
- const exactNetworkFeeWei = await gateway.getFunction("quoteBridgeOut")(
1013
+ const taoAmount = input.source === "liquid" ? input.amountWei : 0n;
1014
+ const stakedAlphaRao = input.source === "staked" ? input.amountWei / EVM_WEI_PER_RAO : 0n;
1015
+ const exactNetworkFeeWei = partnerFee.bps === 0 ? await provider.readContract({
1016
+ address: subtensor.contracts.gateway,
1017
+ abi: alphaAbi,
1018
+ functionName: "quoteBridgeOut",
1019
+ args: [
1020
+ evm.ccipSelector,
1021
+ asset.subtensorToken,
1022
+ recipient,
1023
+ input.amountWei
1024
+ ]
1025
+ }) : (await quoteHubWithFee(
1026
+ provider,
1027
+ subtensor.contracts.gateway,
738
1028
  evm.ccipSelector,
739
- subtensor.contracts.wrappedTao,
1029
+ asset.subtensorToken,
740
1030
  recipient,
741
- input.amountWei
742
- );
1031
+ input.amountWei,
1032
+ taoAmount,
1033
+ stakedAlphaRao,
1034
+ partnerFee
1035
+ )).networkFee;
743
1036
  let stakingAllowanceRao;
744
1037
  if (input.source === "staked") {
745
- if (input.netuid === void 0) {
746
- throw new ForeverMoneyError(
747
- "INVALID_TRANSACTION_PLAN",
748
- "A netuid is required when bridging staked TAO."
749
- );
750
- }
751
- assertNonNegativeAmount(input.netuid, "netuid");
752
- const staking = new Contract(
753
- subtensor.contracts.stakingPrecompile,
754
- STAKING_ABI,
755
- provider
756
- );
757
- stakingAllowanceRao = await staking.getFunction("allowance")(
758
- sender,
759
- subtensor.contracts.gateway,
760
- input.netuid
761
- );
1038
+ stakingAllowanceRao = await provider.readContract({
1039
+ address: subtensor.contracts.stakingPrecompile,
1040
+ abi: stakingAbi,
1041
+ functionName: "allowance",
1042
+ args: [sender, subtensor.contracts.gateway, netuid]
1043
+ });
762
1044
  }
763
- const taoAmount = input.source === "liquid" ? input.amountWei : 0n;
764
- const stakedAlphaRao = input.source === "staked" ? input.amountWei / EVM_WEI_PER_RAO : 0n;
765
- const value = taoAmount + feeWithBuffer(exactNetworkFeeWei);
1045
+ const alphaTopUpRao = partnerFeeCut(stakedAlphaRao, partnerFee.bps);
1046
+ const taoTopUp = partnerFeeTaoTopUp(taoAmount, partnerFee.bps);
1047
+ const value = taoAmount + taoTopUp + feeWithBuffer(exactNetworkFeeWei);
766
1048
  assertNonNegativeAmount(value, "Transaction value");
767
1049
  let estimatedBridgeGas;
768
- if (input.source === "liquid" || stakingAllowanceRao !== void 0 && stakingAllowanceRao >= stakedAlphaRao) {
1050
+ if (input.source === "liquid" || stakingAllowanceRao !== void 0 && stakingAllowanceRao >= stakedAlphaRao + alphaTopUpRao) {
769
1051
  estimatedBridgeGas = await provider.estimateGas({
770
- from: sender,
1052
+ account: sender,
771
1053
  to: subtensor.contracts.gateway,
772
- data: alphaInterface.encodeFunctionData("bridgeOut", [
1054
+ data: encodeHubBridge(
773
1055
  evm.ccipSelector,
774
- subtensor.contracts.wrappedTao,
1056
+ asset.subtensorToken,
775
1057
  recipient,
776
1058
  taoAmount,
777
1059
  stakedAlphaRao,
778
- input.amountWei
779
- ]),
1060
+ input.amountWei,
1061
+ partnerFee
1062
+ ),
780
1063
  value
781
1064
  });
782
1065
  }
@@ -789,6 +1072,7 @@ async function prepareSubtensorToEvm(provider, input) {
789
1072
  return Object.freeze({
790
1073
  exactNetworkFeeWei,
791
1074
  transactionValueWei: value,
1075
+ partnerFeeWei: input.source === "liquid" ? taoTopUp : alphaTopUpRao * EVM_WEI_PER_RAO,
792
1076
  plan
793
1077
  });
794
1078
  }
@@ -797,7 +1081,7 @@ function prepareSubtensorToBase(provider, input) {
797
1081
  }
798
1082
 
799
1083
  // src/core/transport.ts
800
- import { BrowserProvider } from "ethers";
1084
+ import { createPublicClient, custom } from "viem";
801
1085
  function isRecord(value) {
802
1086
  return typeof value === "object" && value !== null && !Array.isArray(value);
803
1087
  }
@@ -916,10 +1200,42 @@ function providerFromTransport(transport) {
916
1200
  "An EIP-1193-compatible RPC transport is required."
917
1201
  );
918
1202
  }
919
- return new BrowserProvider(transport);
1203
+ return createPublicClient({
1204
+ transport: custom(transport, { retryCount: 0 }),
1205
+ cacheTime: 0,
1206
+ batch: { multicall: false }
1207
+ });
1208
+ }
1209
+ function trackingClient(provider) {
1210
+ if (provider && "getChainId" in provider && typeof provider.getChainId === "function")
1211
+ return provider;
1212
+ if (provider && "send" in provider && typeof provider.send === "function") {
1213
+ return providerFromTransport({
1214
+ request: ({ method, params }) => {
1215
+ if (params !== void 0 && !Array.isArray(params))
1216
+ throw new ForeverMoneyError(
1217
+ "RPC_ERROR",
1218
+ "Tracking RPC params must be an array."
1219
+ );
1220
+ return provider.send(
1221
+ method,
1222
+ params === void 0 ? [] : [...params]
1223
+ );
1224
+ }
1225
+ });
1226
+ }
1227
+ throw new ForeverMoneyError(
1228
+ "MISSING_TRANSPORT",
1229
+ "A viem public client or JSON-RPC provider is required."
1230
+ );
920
1231
  }
921
1232
 
922
1233
  // src/core/provider-errors.ts
1234
+ import {
1235
+ BaseError,
1236
+ ContractFunctionRevertedError,
1237
+ ExecutionRevertedError
1238
+ } from "viem";
923
1239
  function stringProperty(value, property) {
924
1240
  if (typeof value !== "object" || value === null || !(property in value)) {
925
1241
  return void 0;
@@ -932,9 +1248,13 @@ async function providerOperation(operation, action) {
932
1248
  return await action();
933
1249
  } catch (error) {
934
1250
  if (error instanceof ForeverMoneyError) throw error;
935
- const causeCode = stringProperty(error, "code");
936
- const reason = stringProperty(error, "reason");
937
- const reverted = causeCode === "CALL_EXCEPTION";
1251
+ const revert = error instanceof BaseError ? error.walk(
1252
+ (cause) => cause instanceof ContractFunctionRevertedError || cause instanceof ExecutionRevertedError
1253
+ ) : void 0;
1254
+ const viemRevert = revert instanceof ContractFunctionRevertedError || revert instanceof ExecutionRevertedError;
1255
+ const causeCode = viemRevert ? revert.name : stringProperty(error, "code");
1256
+ const reason = viemRevert ? revert instanceof ContractFunctionRevertedError ? revert.data?.errorName ?? revert.reason : void 0 : stringProperty(error, "reason");
1257
+ const reverted = viemRevert || causeCode === "CALL_EXCEPTION";
938
1258
  throw new ForeverMoneyError(
939
1259
  reverted ? "SIMULATION_REVERTED" : "RPC_ERROR",
940
1260
  reverted ? `${operation} reverted.` : `${operation} failed.`,
@@ -947,10 +1267,14 @@ async function providerOperation(operation, action) {
947
1267
  }
948
1268
 
949
1269
  // src/vaults/plans.ts
950
- import { Contract as Contract2, Interface as Interface2, ZeroAddress as ZeroAddress2 } from "ethers";
951
- var erc20Interface2 = new Interface2(ERC20_ABI);
952
- var factoryInterface = new Interface2(VAULT_FACTORY_ABI);
953
- var managerInterface = new Interface2(VAULT_MANAGER_ABI);
1270
+ import {
1271
+ encodeFunctionData as encodeFunctionData2,
1272
+ parseAbi as parseAbi2,
1273
+ zeroAddress as zeroAddress2
1274
+ } from "viem";
1275
+ var erc20Abi2 = parseAbi2(ERC20_ABI);
1276
+ var factoryAbi = parseAbi2(VAULT_FACTORY_ABI);
1277
+ var managerAbi = parseAbi2(VAULT_MANAGER_ABI);
954
1278
  function step(kind, label, from, to, data, value = 0n) {
955
1279
  return {
956
1280
  kind,
@@ -1067,10 +1391,11 @@ function buildCreateVaultPlan(input) {
1067
1391
  `Approve ${stash.token} for the vault factory`,
1068
1392
  owner,
1069
1393
  stash.token,
1070
- erc20Interface2.encodeFunctionData("approve", [
1071
- base.contracts.vaultFactory,
1072
- stash.amount
1073
- ])
1394
+ encodeFunctionData2({
1395
+ abi: erc20Abi2,
1396
+ functionName: "approve",
1397
+ args: [base.contracts.vaultFactory, stash.amount]
1398
+ })
1074
1399
  )
1075
1400
  );
1076
1401
  }
@@ -1081,15 +1406,19 @@ function buildCreateVaultPlan(input) {
1081
1406
  "Create ForeverMoney vault",
1082
1407
  owner,
1083
1408
  base.contracts.vaultFactory,
1084
- factoryInterface.encodeFunctionData("create", [
1085
- owner,
1086
- associatedMiner,
1087
- akAddress,
1088
- poolManager,
1089
- poolAddress,
1090
- positionManagerImplementation,
1091
- stashTokens
1092
- ]),
1409
+ encodeFunctionData2({
1410
+ abi: factoryAbi,
1411
+ functionName: "create",
1412
+ args: [
1413
+ owner,
1414
+ associatedMiner,
1415
+ akAddress,
1416
+ poolManager,
1417
+ poolAddress,
1418
+ positionManagerImplementation,
1419
+ stashTokens
1420
+ ]
1421
+ }),
1093
1422
  value
1094
1423
  )
1095
1424
  );
@@ -1108,14 +1437,15 @@ async function prepareCreateVault(provider, input) {
1108
1437
  const allowances = await Promise.all(
1109
1438
  erc20Stash.map(async ({ token }) => ({
1110
1439
  token,
1111
- allowance: await new Contract2(
1112
- token,
1113
- ERC20_ABI,
1114
- provider
1115
- ).getFunction("allowance")(
1116
- owner,
1117
- foreverMoneyDeployment.base.contracts.vaultFactory
1118
- )
1440
+ allowance: await provider.readContract({
1441
+ address: token,
1442
+ abi: erc20Abi2,
1443
+ functionName: "allowance",
1444
+ args: [
1445
+ owner,
1446
+ foreverMoneyDeployment.base.contracts.vaultFactory
1447
+ ]
1448
+ })
1119
1449
  }))
1120
1450
  );
1121
1451
  return buildCreateVaultPlan({ ...input, allowances });
@@ -1142,11 +1472,11 @@ function buildDepositVaultPlan(input) {
1142
1472
  "Deposit native ETH into the vault as WETH",
1143
1473
  owner,
1144
1474
  manager,
1145
- managerInterface.encodeFunctionData("topUpAk", [
1146
- akAddress,
1147
- ZeroAddress2,
1148
- deposit.amount
1149
- ]),
1475
+ encodeFunctionData2({
1476
+ abi: managerAbi,
1477
+ functionName: "topUpAk",
1478
+ args: [akAddress, zeroAddress2, deposit.amount]
1479
+ }),
1150
1480
  deposit.amount
1151
1481
  )
1152
1482
  );
@@ -1166,10 +1496,11 @@ function buildDepositVaultPlan(input) {
1166
1496
  `Approve ${deposit.token} for the vault manager`,
1167
1497
  owner,
1168
1498
  deposit.token,
1169
- erc20Interface2.encodeFunctionData("approve", [
1170
- manager,
1171
- deposit.amount
1172
- ])
1499
+ encodeFunctionData2({
1500
+ abi: erc20Abi2,
1501
+ functionName: "approve",
1502
+ args: [manager, deposit.amount]
1503
+ })
1173
1504
  )
1174
1505
  );
1175
1506
  }
@@ -1179,11 +1510,11 @@ function buildDepositVaultPlan(input) {
1179
1510
  `Deposit ${deposit.token} into the vault`,
1180
1511
  owner,
1181
1512
  manager,
1182
- managerInterface.encodeFunctionData("topUpAk", [
1183
- akAddress,
1184
- deposit.token,
1185
- deposit.amount
1186
- ])
1513
+ encodeFunctionData2({
1514
+ abi: managerAbi,
1515
+ functionName: "topUpAk",
1516
+ args: [akAddress, deposit.token, deposit.amount]
1517
+ })
1187
1518
  )
1188
1519
  );
1189
1520
  }
@@ -1203,11 +1534,12 @@ async function prepareDepositVault(provider, input) {
1203
1534
  const allowances = await Promise.all(
1204
1535
  erc20Deposits.map(async ({ token }) => ({
1205
1536
  token,
1206
- allowance: await new Contract2(
1207
- token,
1208
- ERC20_ABI,
1209
- provider
1210
- ).getFunction("allowance")(owner, manager)
1537
+ allowance: await provider.readContract({
1538
+ address: token,
1539
+ abi: erc20Abi2,
1540
+ functionName: "allowance",
1541
+ args: [owner, manager]
1542
+ })
1211
1543
  }))
1212
1544
  );
1213
1545
  return buildDepositVaultPlan({ ...input, allowances });
@@ -1238,16 +1570,17 @@ function buildWithdrawVaultPlan(input) {
1238
1570
  "Withdraw assets from the vault",
1239
1571
  owner,
1240
1572
  manager,
1241
- managerInterface.encodeFunctionData(
1242
- "withdrawFromAkAndPositions",
1243
- [
1573
+ encodeFunctionData2({
1574
+ abi: managerAbi,
1575
+ functionName: "withdrawFromAkAndPositions",
1576
+ args: [
1244
1577
  akAddress,
1245
1578
  input.amount0,
1246
1579
  input.amount1,
1247
1580
  input.decreaseTokenIds,
1248
1581
  input.unwrapWeth
1249
1582
  ]
1250
- )
1583
+ })
1251
1584
  )
1252
1585
  ]
1253
1586
  });
@@ -1265,9 +1598,11 @@ function buildClaimVaultFeesPlan(input) {
1265
1598
  "Claim vault fees",
1266
1599
  owner,
1267
1600
  manager,
1268
- managerInterface.encodeFunctionData("claimFees(address)", [
1269
- akAddress
1270
- ])
1601
+ encodeFunctionData2({
1602
+ abi: managerAbi,
1603
+ functionName: "claimFees",
1604
+ args: [akAddress]
1605
+ })
1271
1606
  )
1272
1607
  ]
1273
1608
  });
@@ -1287,20 +1622,25 @@ function buildSetVaultStakingPlan(input) {
1287
1622
  `${input.staking ? "Stake" : "Unstake"} the vault position`,
1288
1623
  owner,
1289
1624
  manager,
1290
- managerInterface.encodeFunctionData(
1291
- `${action}(address,bytes)`,
1292
- [akAddress, "0x"]
1293
- )
1625
+ encodeFunctionData2({
1626
+ abi: managerAbi,
1627
+ functionName: action,
1628
+ args: [akAddress, "0x"]
1629
+ })
1294
1630
  )
1295
1631
  ]
1296
1632
  });
1297
1633
  }
1298
1634
 
1299
1635
  // src/bridge/tracking.ts
1300
- import { Interface as Interface4, toBeHex } from "ethers";
1636
+ import {
1637
+ decodeEventLog as decodeEventLog2,
1638
+ parseAbi as parseAbi4,
1639
+ TransactionReceiptNotFoundError
1640
+ } from "viem";
1301
1641
 
1302
1642
  // src/bridge/receipts.ts
1303
- import { Interface as Interface3, isHexString as isHexString2 } from "ethers";
1643
+ import { decodeEventLog, isHex as isHex2, parseAbi as parseAbi3 } from "viem";
1304
1644
 
1305
1645
  // src/core/receipts.ts
1306
1646
  function isLogFrom(log, address) {
@@ -1308,8 +1648,8 @@ function isLogFrom(log, address) {
1308
1648
  }
1309
1649
 
1310
1650
  // src/bridge/receipts.ts
1311
- var alphaGatewayInterface = new Interface3(ALPHA_GATEWAY_ABI);
1312
- var spokeGatewayInterface = new Interface3(SPOKE_GATEWAY_ABI);
1651
+ var alphaGatewayAbi = parseAbi3(ALPHA_GATEWAY_ABI);
1652
+ var spokeGatewayAbi = parseAbi3(SPOKE_GATEWAY_ABI);
1313
1653
  function assertBridgeDirection(value) {
1314
1654
  if (value !== "base-to-subtensor" && value !== "robinhood-to-subtensor" && value !== "subtensor-to-base" && value !== "subtensor-to-robinhood") {
1315
1655
  throw new ForeverMoneyError(
@@ -1332,20 +1672,28 @@ function bridgeMessageIdFromReceipt(direction, receipt) {
1332
1672
  evmChainFromBridgeDirection(direction)
1333
1673
  );
1334
1674
  const evmToSubtensor = isEvmToSubtensorDirection(direction);
1335
- const [address, contractInterface, eventName] = evmToSubtensor ? [evm.contracts.gateway, spokeGatewayInterface, "BridgedToFinney"] : [
1336
- foreverMoneyDeployment.subtensor.contracts.gateway,
1337
- alphaGatewayInterface,
1675
+ const [addresses, contractAbi, eventName] = evmToSubtensor ? [
1676
+ [evm.contracts.legacyGateway, evm.contracts.gateway],
1677
+ spokeGatewayAbi,
1678
+ "BridgedToFinney"
1679
+ ] : [
1680
+ [
1681
+ foreverMoneyDeployment.subtensor.contracts.legacyGateway,
1682
+ foreverMoneyDeployment.subtensor.contracts.gateway
1683
+ ],
1684
+ alphaGatewayAbi,
1338
1685
  "BridgedOut"
1339
1686
  ];
1340
1687
  for (const log of receipt.logs) {
1341
- if (!isLogFrom(log, address)) continue;
1688
+ if (!addresses.some((address) => isLogFrom(log, address))) continue;
1342
1689
  try {
1343
- const parsed = contractInterface.parseLog({
1690
+ const parsed = decodeEventLog({
1691
+ abi: contractAbi,
1344
1692
  data: log.data,
1345
1693
  topics: [...log.topics]
1346
1694
  });
1347
- const messageId = parsed?.args.messageId;
1348
- if (parsed?.name === eventName && typeof messageId === "string" && isHexString2(messageId, 32) && (evmToSubtensor || parsed.args.destChainSelector === evm.ccipSelector)) {
1695
+ const messageId = "messageId" in parsed.args ? parsed.args.messageId : void 0;
1696
+ 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
1697
  return messageId.toLowerCase();
1350
1698
  }
1351
1699
  } catch {
@@ -1355,8 +1703,8 @@ function bridgeMessageIdFromReceipt(direction, receipt) {
1355
1703
  }
1356
1704
 
1357
1705
  // src/bridge/tracking.ts
1358
- var ccipExecutionInterface = new Interface4(CCIP_EXECUTION_ABI);
1359
- var alphaGatewayInterface2 = new Interface4(ALPHA_GATEWAY_ABI);
1706
+ var ccipExecutionAbi = parseAbi4(CCIP_EXECUTION_ABI);
1707
+ var alphaGatewayAbi2 = parseAbi4(ALPHA_GATEWAY_ABI);
1360
1708
  function destinationChainId(direction) {
1361
1709
  assertBridgeDirection(direction);
1362
1710
  const evm = getForeverMoneyEvmDeployment(
@@ -1372,14 +1720,14 @@ function sourceChainId(direction) {
1372
1720
  return isEvmToSubtensorDirection(direction) ? evm.chainId : foreverMoneyDeployment.subtensor.chainId;
1373
1721
  }
1374
1722
  async function assertProviderChain(provider, expectedChainId, label) {
1375
- const network = await provider.getNetwork();
1376
- if (network.chainId !== BigInt(expectedChainId)) {
1723
+ const chainId = await provider.getChainId();
1724
+ if (chainId !== expectedChainId) {
1377
1725
  throw new ForeverMoneyError(
1378
1726
  "CHAIN_MISMATCH",
1379
- `${label} transport reported chain ID ${network.chainId}; expected ${expectedChainId}.`,
1727
+ `${label} transport reported chain ID ${chainId}; expected ${expectedChainId}.`,
1380
1728
  {
1381
1729
  expectedChainId,
1382
- actualChainId: network.chainId.toString()
1730
+ actualChainId: chainId.toString()
1383
1731
  }
1384
1732
  );
1385
1733
  }
@@ -1390,13 +1738,14 @@ async function assertDestinationProvider(provider, direction) {
1390
1738
  return expectedChainId;
1391
1739
  }
1392
1740
  async function getBridgeSourceStatus(provider, input) {
1741
+ const client = trackingClient(provider);
1393
1742
  const expectedChainId = sourceChainId(input.direction);
1394
1743
  const transactionHash = normalizeBytes32(
1395
1744
  input.transactionHash,
1396
1745
  "Transaction hash"
1397
1746
  );
1398
- await assertProviderChain(provider, expectedChainId, "Bridge source");
1399
- const receipt = await provider.getTransactionReceipt(transactionHash);
1747
+ await assertProviderChain(client, expectedChainId, "Bridge source");
1748
+ const receipt = await receiptOrNull(client, transactionHash);
1400
1749
  if (receipt === null) {
1401
1750
  return Object.freeze({
1402
1751
  direction: input.direction,
@@ -1406,7 +1755,7 @@ async function getBridgeSourceStatus(provider, input) {
1406
1755
  messageId: null
1407
1756
  });
1408
1757
  }
1409
- if (receipt.status === 0) {
1758
+ if (receipt.status === "reverted") {
1410
1759
  return Object.freeze({
1411
1760
  direction: input.direction,
1412
1761
  sourceChainId: expectedChainId,
@@ -1415,7 +1764,7 @@ async function getBridgeSourceStatus(provider, input) {
1415
1764
  messageId: null
1416
1765
  });
1417
1766
  }
1418
- if (receipt.status !== 1) {
1767
+ if (receipt.status !== "success") {
1419
1768
  throw new ForeverMoneyError(
1420
1769
  "INVALID_PROVIDER_RESPONSE",
1421
1770
  "The bridge source receipt has an invalid status."
@@ -1437,8 +1786,10 @@ async function getBridgeSourceStatus(provider, input) {
1437
1786
  });
1438
1787
  }
1439
1788
  async function getCcipDeliveryCheckpoint(provider, direction) {
1440
- const expectedChainId = await assertDestinationProvider(provider, direction);
1441
- const fromBlock = await provider.getBlockNumber();
1789
+ const client = trackingClient(provider);
1790
+ const expectedChainId = await assertDestinationProvider(client, direction);
1791
+ const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
1792
+ const fromBlock = Number(blockNumber);
1442
1793
  if (!Number.isSafeInteger(fromBlock) || fromBlock < 0) {
1443
1794
  throw new ForeverMoneyError(
1444
1795
  "INVALID_PROVIDER_RESPONSE",
@@ -1452,6 +1803,7 @@ async function getCcipDeliveryCheckpoint(provider, direction) {
1452
1803
  });
1453
1804
  }
1454
1805
  async function getCcipDeliveryStatus(provider, input) {
1806
+ const client = trackingClient(provider);
1455
1807
  const expectedChainId = destinationChainId(input.direction);
1456
1808
  const messageId = normalizeBytes32(input.messageId, "CCIP message ID");
1457
1809
  if (!Number.isSafeInteger(input.fromBlock) || input.fromBlock < 0) {
@@ -1460,42 +1812,50 @@ async function getCcipDeliveryStatus(provider, input) {
1460
1812
  "CCIP fromBlock must be a non-negative safe integer."
1461
1813
  );
1462
1814
  }
1463
- await assertProviderChain(provider, expectedChainId, "Bridge destination");
1464
- const event = ccipExecutionInterface.getEvent("ExecutionStateChanged");
1465
- if (event === null) {
1466
- throw new Error("CCIP execution event is missing from the SDK ABI.");
1467
- }
1815
+ await assertProviderChain(client, expectedChainId, "Bridge destination");
1468
1816
  const evmChain = evmChainFromBridgeDirection(input.direction);
1469
1817
  const evm = getForeverMoneyEvmDeployment(evmChain);
1470
1818
  const evmToSubtensor = isEvmToSubtensorDirection(input.direction);
1471
1819
  const sourceSelector = evmToSubtensor ? evm.ccipSelector : foreverMoneyDeployment.subtensor.ccipSelector;
1472
1820
  const offRamp = evmToSubtensor ? evmChain === "base" ? foreverMoneyDeployment.subtensor.contracts.ccipOffRampFromBase : foreverMoneyDeployment.subtensor.contracts.ccipOffRampFromRobinhood : evm.contracts.ccipOffRampFromSubtensor;
1473
- const logs = await provider.getLogs({
1821
+ const logs = await client.getLogs({
1474
1822
  address: offRamp,
1475
- fromBlock: input.fromBlock,
1823
+ fromBlock: BigInt(input.fromBlock),
1476
1824
  toBlock: "latest",
1477
- topics: [event.topicHash, toBeHex(sourceSelector, 32), null, messageId]
1825
+ event: ccipExecutionAbi[0],
1826
+ args: { sourceChainSelector: sourceSelector, messageId },
1827
+ strict: true
1478
1828
  });
1479
1829
  const latest = logs.at(-1);
1480
1830
  if (latest === void 0) return "waiting";
1481
- const parsed = ccipExecutionInterface.parseLog(latest);
1482
- const state = Number(parsed?.args.state);
1831
+ const state = latest.args.state;
1483
1832
  if (state === 3) return "failure";
1484
1833
  if (state !== 2) return "waiting";
1485
1834
  if (!evmToSubtensor) return "success";
1486
- const receipt = await provider.getTransactionReceipt(latest.transactionHash);
1835
+ const receipt = await receiptOrNull(client, latest.transactionHash);
1487
1836
  if (receipt === null) {
1488
1837
  throw new ForeverMoneyError(
1489
1838
  "INVALID_PROVIDER_RESPONSE",
1490
1839
  "The CCIP execution receipt is unavailable."
1491
1840
  );
1492
1841
  }
1842
+ const subtensorGateways = [
1843
+ foreverMoneyDeployment.subtensor.contracts.legacyGateway,
1844
+ foreverMoneyDeployment.subtensor.contracts.gateway
1845
+ ];
1493
1846
  for (const log of receipt.logs) {
1494
- if (log.address.toLowerCase() !== foreverMoneyDeployment.subtensor.contracts.gateway.toLowerCase()) {
1847
+ if (!subtensorGateways.some(
1848
+ (gateway) => log.address.toLowerCase() === gateway.toLowerCase()
1849
+ )) {
1495
1850
  continue;
1496
1851
  }
1497
1852
  try {
1498
- if (alphaGatewayInterface2.parseLog(log)?.name === "Claimable") {
1853
+ const { eventName } = decodeEventLog2({
1854
+ abi: alphaGatewayAbi2,
1855
+ data: log.data,
1856
+ topics: log.topics
1857
+ });
1858
+ if (eventName === "Claimable" || eventName === "NotDelivered") {
1499
1859
  return "recovery";
1500
1860
  }
1501
1861
  } catch {
@@ -1503,20 +1863,28 @@ async function getCcipDeliveryStatus(provider, input) {
1503
1863
  }
1504
1864
  return "success";
1505
1865
  }
1866
+ async function receiptOrNull(provider, hash) {
1867
+ try {
1868
+ return await provider.getTransactionReceipt({ hash });
1869
+ } catch (error) {
1870
+ if (error instanceof TransactionReceiptNotFoundError) return null;
1871
+ throw error;
1872
+ }
1873
+ }
1506
1874
 
1507
1875
  // src/client.ts
1508
1876
  async function assertProviderChain2(provider, expectedChainId, name) {
1509
- const network = await providerOperation(
1877
+ const chainId = await providerOperation(
1510
1878
  `Reading the ${name} chain ID`,
1511
- () => provider.getNetwork()
1879
+ () => provider.getChainId()
1512
1880
  );
1513
- if (network.chainId !== BigInt(expectedChainId)) {
1881
+ if (chainId !== expectedChainId) {
1514
1882
  throw new ForeverMoneyError(
1515
1883
  "CHAIN_MISMATCH",
1516
- `${name} transport reported chain ID ${network.chainId}; expected ${expectedChainId}.`,
1884
+ `${name} transport reported chain ID ${chainId}; expected ${expectedChainId}.`,
1517
1885
  {
1518
1886
  expectedChainId,
1519
- actualChainId: network.chainId.toString()
1887
+ actualChainId: chainId.toString()
1520
1888
  }
1521
1889
  );
1522
1890
  }
@@ -1648,19 +2016,20 @@ function createForeverMoneyClient(options) {
1648
2016
  }
1649
2017
 
1650
2018
  // src/vaults/receipts.ts
1651
- import { Interface as Interface5 } from "ethers";
1652
- var vaultFactoryInterface = new Interface5(VAULT_FACTORY_ABI);
2019
+ import { decodeEventLog as decodeEventLog3, parseAbi as parseAbi5 } from "viem";
2020
+ var vaultFactoryAbi = parseAbi5(VAULT_FACTORY_ABI);
1653
2021
  function vaultManagerFromCreationReceipt(receipt) {
1654
2022
  for (const log of receipt.logs) {
1655
2023
  if (!isLogFrom(log, foreverMoneyDeployment.base.contracts.vaultFactory)) {
1656
2024
  continue;
1657
2025
  }
1658
2026
  try {
1659
- const parsed = vaultFactoryInterface.parseLog({
2027
+ const parsed = decodeEventLog3({
2028
+ abi: vaultFactoryAbi,
1660
2029
  data: log.data,
1661
2030
  topics: [...log.topics]
1662
2031
  });
1663
- if (parsed?.name === "SnLiquidityManagerCreated") {
2032
+ if (parsed.eventName === "SnLiquidityManagerCreated") {
1664
2033
  return normalizeEvmAddress(String(parsed.args.manager));
1665
2034
  }
1666
2035
  } catch {
@@ -1670,7 +2039,10 @@ function vaultManagerFromCreationReceipt(receipt) {
1670
2039
  }
1671
2040
 
1672
2041
  // src/core/transactions.ts
1673
- import { MaxUint256 as MaxUint2563 } from "ethers";
2042
+ import {
2043
+ defineChain,
2044
+ maxUint256 as maxUint2563
2045
+ } from "viem";
1674
2046
  function decimalQuantity(value, label) {
1675
2047
  if (!/^(0|[1-9][0-9]*)$/.test(value)) {
1676
2048
  throw new ForeverMoneyError(
@@ -1679,7 +2051,7 @@ function decimalQuantity(value, label) {
1679
2051
  );
1680
2052
  }
1681
2053
  const quantity = BigInt(value);
1682
- if (quantity > MaxUint2563) {
2054
+ if (quantity > maxUint2563) {
1683
2055
  throw new ForeverMoneyError(
1684
2056
  "INVALID_TRANSACTION_PLAN",
1685
2057
  `${label} exceeds uint256.`
@@ -1715,6 +2087,52 @@ function toEthersTransaction(transaction) {
1715
2087
  }
1716
2088
  });
1717
2089
  }
2090
+ var transactionChains = new Map(
2091
+ [
2092
+ [BASE_CHAIN_ID, "Base", "Ether", "ETH"],
2093
+ [ROBINHOOD_CHAIN_ID, "Robinhood", "Ether", "ETH"],
2094
+ [SUBTENSOR_CHAIN_ID, "Subtensor", "TAO", "TAO"]
2095
+ ].map(([id, name, currency, symbol]) => [
2096
+ id,
2097
+ Object.freeze(
2098
+ defineChain({
2099
+ id,
2100
+ name,
2101
+ nativeCurrency: Object.freeze({
2102
+ name: currency,
2103
+ symbol,
2104
+ decimals: 18
2105
+ }),
2106
+ // Chain identity only. The caller retains ownership of the wallet transport.
2107
+ rpcUrls: Object.freeze({
2108
+ default: Object.freeze({ http: Object.freeze([]) })
2109
+ })
2110
+ })
2111
+ )
2112
+ ])
2113
+ );
2114
+ function toViemTransaction(transaction) {
2115
+ const chain = transactionChains.get(transaction.chainId);
2116
+ if (!chain)
2117
+ throw new ForeverMoneyError(
2118
+ "INVALID_TRANSACTION_PLAN",
2119
+ "Unsupported transaction chain."
2120
+ );
2121
+ return Object.freeze({
2122
+ chain,
2123
+ account: transaction.from,
2124
+ chainId: transaction.chainId,
2125
+ to: transaction.to,
2126
+ data: transaction.data,
2127
+ value: decimalQuantity(transaction.value, "Transaction value"),
2128
+ ...transaction.gasLimit === void 0 ? {} : {
2129
+ gas: decimalQuantity(
2130
+ transaction.gasLimit,
2131
+ "Transaction gas limit"
2132
+ )
2133
+ }
2134
+ });
2135
+ }
1718
2136
  export {
1719
2137
  BASE_CCIP_SELECTOR,
1720
2138
  BASE_CHAIN_ID,
@@ -1723,12 +2141,15 @@ export {
1723
2141
  FOREVERMONEY_DEPLOYMENT_VERSION,
1724
2142
  ForeverMoneyError,
1725
2143
  GAS_LIMIT_BUFFER_BPS,
2144
+ MAX_PARTNER_FEE_BPS,
1726
2145
  MIN_LIQUID_BASE_TO_SUBTENSOR_WEI,
1727
2146
  MIN_LIQUID_EVM_TO_SUBTENSOR_WEI,
2147
+ MIN_LIQUID_SUBTENSOR_TO_EVM_WEI,
1728
2148
  NETWORK_FEE_BUFFER_BPS,
1729
2149
  RAO_PER_TAO,
1730
2150
  ROBINHOOD_CCIP_SELECTOR,
1731
2151
  ROBINHOOD_CHAIN_ID,
2152
+ SN80_NETUID,
1732
2153
  SUBTENSOR_CCIP_SELECTOR,
1733
2154
  SUBTENSOR_CHAIN_ID,
1734
2155
  assertWholeRao,
@@ -1761,10 +2182,13 @@ export {
1761
2182
  normalizeEvmAddress,
1762
2183
  normalizeSS58,
1763
2184
  parseTaoAmount,
2185
+ partnerFeeCut,
2186
+ partnerFeeTaoTopUp,
1764
2187
  sourceChainId,
1765
2188
  ss58ToPublicKey,
1766
2189
  toEip1193Transaction,
1767
2190
  toEthersTransaction,
2191
+ toViemTransaction,
1768
2192
  vaultManagerFromCreationReceipt
1769
2193
  };
1770
2194
  //# sourceMappingURL=index.js.map