@forevermoney/sdk 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.3 — 2026-09-19
4
+
5
+ - Increased EVM-to-Subtensor CCIP destination execution gas from the spoke
6
+ gateways' 300,000 default to an explicit 3,500,000. A 900,000 manual
7
+ execution reached the gateway but still fell back to a claimable booking;
8
+ the same live liquid claim path estimates near 2,560,000 gas. Quotes and
9
+ transaction calldata now use the same exported
10
+ `EVM_TO_SUBTENSOR_DESTINATION_GAS_LIMIT` for zero-fee and partner-fee
11
+ bridges. Callers can override it per transaction with the optional
12
+ `destinationGasLimit` request field, without changing or republishing the
13
+ SDK.
14
+ - Added the explicit-gas `quoteBridgeToFinney` and `bridgeToFinney` overloads
15
+ to the public SpokeGateway ABI.
16
+
3
17
  ## 0.5.2 — 2026-09-16
4
18
 
5
19
  - Added opt-in stake rounding adjustment to Subtensor bridge preparation, with an explicit disable option and adjusted amount/plan metadata. Searches only on `StrandedStake`, preserves minimum output, requotes candidates and checks source balances, minimum remainders and partner-fee allocations. Approval-required plans are explicitly marked as not yet simulated.
package/README.md CHANGED
@@ -6,10 +6,10 @@ vault contracts.
6
6
  The SDK owns the canonical production deployment: chain IDs, CCIP selectors,
7
7
  contract addresses, ABIs, and protocol-specific amount conversion. An
8
8
  integrator supplies only RPC transports and user input. The SDK never accepts a
9
- private key, signs a transaction, or broadcasts a transaction. Bridge principal
10
- is transferred 1:1 and the network fee is charged separately, so the SDK fixes
11
- the contract's minimum destination output to the bridged principal instead of
12
- exposing configurable slippage.
9
+ private key, signs a transaction, or broadcasts a transaction. Network fees are
10
+ charged separately. Subtensor-to-EVM requests accept an explicit minimum output
11
+ to account for native staking rounding; exact output remains the default.
12
+ SDK 0.5.2 also provides opt-in stake rounding preparation (see below).
13
13
 
14
14
  Bridge plans use the current gateways in `contracts.gateway`. Retired gateways
15
15
  remain under `contracts.legacyGateways` only so receipts and deliveries of
@@ -101,6 +101,11 @@ Liquid Base-to-Subtensor delivery requires at least `0.01 TAO` because the
101
101
  destination vault must unstake the bridged position. The SDK rejects smaller
102
102
  liquid deliveries with `AMOUNT_BELOW_MINIMUM` before quoting or planning them;
103
103
  staked delivery does not use this liquid-unstaking minimum.
104
+ EVM-to-Subtensor plans quote and encode an explicit 3,500,000 destination gas
105
+ limit so the variable-cost Subtensor exit path can auto-execute through CCIP.
106
+ The policy is exported as `EVM_TO_SUBTENSOR_DESTINATION_GAS_LIMIT`. Pass a
107
+ positive bigint as `destinationGasLimit` to override it for one preparation or
108
+ plan; the SDK uses that value for both the fee quote and transaction calldata.
104
109
  The network-fee buffer is 2% and the estimated-gas buffer is 50%; both policies
105
110
  are exported as bigint basis-point constants and covered by property tests.
106
111
 
package/dist/index.cjs CHANGED
@@ -23,6 +23,7 @@ __export(index_exports, {
23
23
  BASE_CCIP_SELECTOR: () => BASE_CCIP_SELECTOR,
24
24
  BASE_CHAIN_ID: () => BASE_CHAIN_ID,
25
25
  BASIS_POINTS: () => BASIS_POINTS,
26
+ EVM_TO_SUBTENSOR_DESTINATION_GAS_LIMIT: () => EVM_TO_SUBTENSOR_DESTINATION_GAS_LIMIT,
26
27
  EVM_WEI_PER_RAO: () => EVM_WEI_PER_RAO,
27
28
  FOREVERMONEY_DEPLOYMENT_VERSION: () => FOREVERMONEY_DEPLOYMENT_VERSION,
28
29
  ForeverMoneyError: () => ForeverMoneyError,
@@ -645,7 +646,9 @@ var SPOKE_GATEWAY_ABI = Object.freeze([
645
646
  "function maxIntegratorFeeBps() view returns (uint16)",
646
647
  "function bridgeFeeBps() view returns (uint16)",
647
648
  "function quoteBridgeToFinney(address token,uint256 amount,(bytes32 ss58,address evmFallback,bool wantLiquid,uint256 minTaoOut) exit) view returns (uint256 fee)",
649
+ "function quoteBridgeToFinney(address token,uint256 amount,(bytes32 ss58,address evmFallback,bool wantLiquid,uint256 minTaoOut) exit,uint256 gasLimit) view returns (uint256 fee)",
648
650
  "function bridgeToFinney(address token,uint256 amount,(bytes32 ss58,address evmFallback,bool wantLiquid,uint256 minTaoOut) exit) payable returns (bytes32 messageId)",
651
+ "function bridgeToFinney(address token,uint256 amount,(bytes32 ss58,address evmFallback,bool wantLiquid,uint256 minTaoOut) exit,uint256 gasLimit) payable returns (bytes32 messageId)",
649
652
  "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)",
650
653
  "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)",
651
654
  "event BridgedToFinney(address indexed token,address indexed sender,bytes32 indexed ss58,uint256 amount,bytes32 messageId)"
@@ -663,7 +666,6 @@ var ALPHA_GATEWAY_ABI = Object.freeze([
663
666
  "function bridgeOutWithFee(uint64 destSelector,address token,address recipient,uint256 taoAmount,uint256 stakedAlphaRao,uint256 minTokenOut,(address recipient,uint16 bps) integrator) payable returns (bytes32 messageId)",
664
667
  "function bridgeOutFromValidators(uint64 destSelector,address token,address recipient,uint256 taoAmount,(bytes32 validator,uint256 alphaRao)[] sources,uint256 minTokenOut) payable returns (bytes32 messageId)",
665
668
  "function bridgeOutFromValidatorsWithFee(uint64 destSelector,address token,address recipient,uint256 taoAmount,(bytes32 validator,uint256 alphaRao)[] sources,uint256 minTokenOut,(address recipient,uint16 bps) integrator) payable returns (bytes32 messageId)",
666
- "function minStakeRequired() view returns (uint256)",
667
669
  "function MAX_STAKE_SOURCES() view returns (uint256)",
668
670
  "function GATEWAY_COLDKEY() view returns (bytes32)",
669
671
  "function claimLiquid(address token,uint256 minTaoOut,address to)",
@@ -750,6 +752,18 @@ var stakingAbi = (0, import_viem6.parseAbi)(STAKING_ABI);
750
752
  var MIN_LIQUID_EVM_TO_SUBTENSOR_WEI = 10000000000000000n;
751
753
  var MIN_LIQUID_BASE_TO_SUBTENSOR_WEI = MIN_LIQUID_EVM_TO_SUBTENSOR_WEI;
752
754
  var MIN_LIQUID_SUBTENSOR_TO_EVM_WEI = 2000000n * EVM_WEI_PER_RAO;
755
+ var EVM_TO_SUBTENSOR_DESTINATION_GAS_LIMIT = 3500000n;
756
+ function resolveDestinationGasLimit(value) {
757
+ const gasLimit = value ?? EVM_TO_SUBTENSOR_DESTINATION_GAS_LIMIT;
758
+ if (typeof gasLimit !== "bigint" || gasLimit <= 0n) {
759
+ throw new ForeverMoneyError(
760
+ "INVALID_TRANSACTION_PLAN",
761
+ "Destination gas limit must be a positive bigint.",
762
+ { destinationGasLimit: String(gasLimit) }
763
+ );
764
+ }
765
+ return gasLimit;
766
+ }
753
767
  var MAX_PARTNER_FEE_BPS = 1e4;
754
768
  var MAX_STAKE_PULLS = 16;
755
769
  var NO_PARTNER_FEE = {
@@ -926,15 +940,15 @@ function partnerFeeSummary(charged, unit, fee) {
926
940
  if (fee.bps === 0) return "";
927
941
  return ` Partner fee: ${charged} wei of ${unit} (${fee.bps} bps) on top, paid to ${fee.recipient}.`;
928
942
  }
929
- function encodeSpokeBridge(token, amountWei, exit, fee) {
943
+ function encodeSpokeBridge(token, amountWei, exit, destinationGasLimit, fee) {
930
944
  return fee.bps === 0 ? (0, import_viem6.encodeFunctionData)({
931
945
  abi: spokeAbi,
932
946
  functionName: "bridgeToFinney",
933
- args: [token, amountWei, exit]
947
+ args: [token, amountWei, exit, destinationGasLimit]
934
948
  }) : (0, import_viem6.encodeFunctionData)({
935
949
  abi: spokeAbi,
936
950
  functionName: "bridgeToFinneyWithFee",
937
- args: [token, amountWei, exit, 0n, fee]
951
+ args: [token, amountWei, exit, destinationGasLimit, fee]
938
952
  });
939
953
  }
940
954
  function resolveStakePulls(pulls, amountRao) {
@@ -1021,7 +1035,7 @@ function encodeHubBridge(destSelector, token, recipient, taoAmount, stakedAlphaR
1021
1035
  args: [...args, fee]
1022
1036
  });
1023
1037
  }
1024
- async function quoteSpokeWithFee(provider, gateway, token, amountWei, exit, fee) {
1038
+ async function quoteSpokeWithFee(provider, gateway, token, amountWei, exit, destinationGasLimit, fee) {
1025
1039
  const maxBps = await provider.readContract({
1026
1040
  address: gateway,
1027
1041
  abi: spokeAbi,
@@ -1032,7 +1046,7 @@ async function quoteSpokeWithFee(provider, gateway, token, amountWei, exit, fee)
1032
1046
  address: gateway,
1033
1047
  abi: spokeAbi,
1034
1048
  functionName: "quoteBridgeToFinneyWithFee",
1035
- args: [token, amountWei, exit, 0n, fee]
1049
+ args: [token, amountWei, exit, destinationGasLimit, fee]
1036
1050
  });
1037
1051
  return networkFee;
1038
1052
  }
@@ -1078,6 +1092,9 @@ function buildEvmToSubtensorPlan(input) {
1078
1092
  assertBaseToSubtensorAmount(input.amountWei, input.delivery);
1079
1093
  assertNonNegativeAmount(input.allowanceWei, "Token allowance");
1080
1094
  assertNonNegativeAmount(input.exactNetworkFeeWei, "Network fee");
1095
+ const destinationGasLimit = resolveDestinationGasLimit(
1096
+ input.destinationGasLimit
1097
+ );
1081
1098
  const destination = normalizeSS58(input.destination);
1082
1099
  const exit = {
1083
1100
  ss58: ss58ToPublicKey(destination),
@@ -1121,6 +1138,7 @@ function buildEvmToSubtensorPlan(input) {
1121
1138
  asset.evmToken,
1122
1139
  input.amountWei,
1123
1140
  exit,
1141
+ destinationGasLimit,
1124
1142
  partnerFee
1125
1143
  ),
1126
1144
  value,
@@ -1236,6 +1254,9 @@ async function prepareEvmToSubtensor(provider, input) {
1236
1254
  assertDelivery(input.delivery);
1237
1255
  assertAssetMode(input.asset, input.delivery);
1238
1256
  assertBaseToSubtensorAmount(input.amountWei, input.delivery);
1257
+ const destinationGasLimit = resolveDestinationGasLimit(
1258
+ input.destinationGasLimit
1259
+ );
1239
1260
  const destination = normalizeSS58(input.destination);
1240
1261
  const evm = getForeverMoneyEvmDeployment(input.evmChain);
1241
1262
  const exit = {
@@ -1260,13 +1281,19 @@ async function prepareEvmToSubtensor(provider, input) {
1260
1281
  address: evm.contracts.gateway,
1261
1282
  abi: spokeAbi,
1262
1283
  functionName: "quoteBridgeToFinney",
1263
- args: [asset.evmToken, input.amountWei, exit]
1284
+ args: [
1285
+ asset.evmToken,
1286
+ input.amountWei,
1287
+ exit,
1288
+ destinationGasLimit
1289
+ ]
1264
1290
  }) : quoteSpokeWithFee(
1265
1291
  provider,
1266
1292
  evm.contracts.gateway,
1267
1293
  asset.evmToken,
1268
1294
  input.amountWei,
1269
1295
  exit,
1296
+ destinationGasLimit,
1270
1297
  partnerFee
1271
1298
  )
1272
1299
  ]);
@@ -1276,6 +1303,7 @@ async function prepareEvmToSubtensor(provider, input) {
1276
1303
  asset.evmToken,
1277
1304
  input.amountWei,
1278
1305
  exit,
1306
+ destinationGasLimit,
1279
1307
  partnerFee
1280
1308
  );
1281
1309
  estimatedBridgeGas = await provider.estimateGas({