@forevermoney/sdk 0.1.0 → 0.2.0

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