@t2000/cli 1.11.4 → 1.13.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.
@@ -23795,21 +23795,26 @@ var WRITE_APPENDER_REGISTRY = {
23795
23795
  throw new T2000Error("INVALID_AMOUNT", "Save amount must be greater than zero");
23796
23796
  }
23797
23797
  const rawAmount = BigInt(Math.floor(input.amount * 10 ** assetInfo.decimals));
23798
- const { coin, effectiveAmount } = await selectAndSplitCoin(
23799
- tx,
23800
- ctx.client,
23801
- ctx.sender,
23802
- assetInfo.type,
23803
- rawAmount
23804
- );
23798
+ let coin;
23799
+ let effectiveAmount;
23800
+ if (ctx.chainedCoin) {
23801
+ coin = ctx.chainedCoin;
23802
+ effectiveAmount = rawAmount;
23803
+ } else {
23804
+ const r = await selectAndSplitCoin(tx, ctx.client, ctx.sender, assetInfo.type, rawAmount);
23805
+ coin = r.coin;
23806
+ effectiveAmount = r.effectiveAmount;
23807
+ }
23805
23808
  if (ctx.feeHooks?.save_deposit) {
23806
23809
  await ctx.feeHooks.save_deposit({ tx, coin, input, sender: ctx.sender });
23807
23810
  }
23808
23811
  await addSaveToTx(tx, ctx.client, ctx.sender, coin, { asset });
23809
23812
  return {
23810
- toolName: "save_deposit",
23811
- effectiveAmount: Number(effectiveAmount) / 10 ** assetInfo.decimals,
23812
- asset
23813
+ preview: {
23814
+ toolName: "save_deposit",
23815
+ effectiveAmount: Number(effectiveAmount) / 10 ** assetInfo.decimals,
23816
+ asset
23817
+ }
23813
23818
  };
23814
23819
  },
23815
23820
  withdraw: async (tx, input, ctx) => {
@@ -23824,8 +23829,13 @@ var WRITE_APPENDER_REGISTRY = {
23824
23829
  input.amount,
23825
23830
  { asset, skipPythUpdate: ctx.sponsoredContext }
23826
23831
  );
23827
- tx.transferObjects([coin], ctx.sender);
23828
- return { toolName: "withdraw", effectiveAmount, asset };
23832
+ if (!ctx.isOutputConsumed) {
23833
+ tx.transferObjects([coin], ctx.sender);
23834
+ }
23835
+ return {
23836
+ preview: { toolName: "withdraw", effectiveAmount, asset },
23837
+ outputCoin: coin
23838
+ };
23829
23839
  },
23830
23840
  borrow: async (tx, input, ctx) => {
23831
23841
  const asset = resolveSaveableAsset(input.asset);
@@ -23842,8 +23852,13 @@ var WRITE_APPENDER_REGISTRY = {
23842
23852
  if (ctx.feeHooks?.borrow) {
23843
23853
  await ctx.feeHooks.borrow({ tx, coin, input, sender: ctx.sender });
23844
23854
  }
23845
- tx.transferObjects([coin], ctx.sender);
23846
- return { toolName: "borrow", effectiveAmount: input.amount, asset };
23855
+ if (!ctx.isOutputConsumed) {
23856
+ tx.transferObjects([coin], ctx.sender);
23857
+ }
23858
+ return {
23859
+ preview: { toolName: "borrow", effectiveAmount: input.amount, asset },
23860
+ outputCoin: coin
23861
+ };
23847
23862
  },
23848
23863
  repay_debt: async (tx, input, ctx) => {
23849
23864
  const asset = resolveSaveableAsset(input.asset);
@@ -23852,21 +23867,26 @@ var WRITE_APPENDER_REGISTRY = {
23852
23867
  throw new T2000Error("INVALID_AMOUNT", "Repay amount must be greater than zero");
23853
23868
  }
23854
23869
  const rawAmount = BigInt(Math.floor(input.amount * 10 ** assetInfo.decimals));
23855
- const { coin, effectiveAmount } = await selectAndSplitCoin(
23856
- tx,
23857
- ctx.client,
23858
- ctx.sender,
23859
- assetInfo.type,
23860
- rawAmount
23861
- );
23870
+ let coin;
23871
+ let effectiveAmount;
23872
+ if (ctx.chainedCoin) {
23873
+ coin = ctx.chainedCoin;
23874
+ effectiveAmount = rawAmount;
23875
+ } else {
23876
+ const r = await selectAndSplitCoin(tx, ctx.client, ctx.sender, assetInfo.type, rawAmount);
23877
+ coin = r.coin;
23878
+ effectiveAmount = r.effectiveAmount;
23879
+ }
23862
23880
  await addRepayToTx(tx, ctx.client, ctx.sender, coin, {
23863
23881
  asset,
23864
23882
  skipOracle: ctx.sponsoredContext
23865
23883
  });
23866
23884
  return {
23867
- toolName: "repay_debt",
23868
- effectiveAmount: Number(effectiveAmount) / 10 ** assetInfo.decimals,
23869
- asset
23885
+ preview: {
23886
+ toolName: "repay_debt",
23887
+ effectiveAmount: Number(effectiveAmount) / 10 ** assetInfo.decimals,
23888
+ asset
23889
+ }
23870
23890
  };
23871
23891
  },
23872
23892
  send_transfer: async (tx, input, ctx) => {
@@ -23882,7 +23902,10 @@ var WRITE_APPENDER_REGISTRY = {
23882
23902
  const rawAmount = BigInt(Math.floor(input.amount * 10 ** assetInfo.decimals));
23883
23903
  let coin;
23884
23904
  let effectiveRaw;
23885
- if (asset === "SUI") {
23905
+ if (ctx.chainedCoin) {
23906
+ coin = ctx.chainedCoin;
23907
+ effectiveRaw = rawAmount;
23908
+ } else if (asset === "SUI") {
23886
23909
  const result = await selectSuiCoin(tx, ctx.client, ctx.sender, rawAmount, ctx.sponsoredContext);
23887
23910
  coin = result.coin;
23888
23911
  effectiveRaw = result.effectiveAmount;
@@ -23893,10 +23916,12 @@ var WRITE_APPENDER_REGISTRY = {
23893
23916
  }
23894
23917
  addSendToTx(tx, coin, recipient);
23895
23918
  return {
23896
- toolName: "send_transfer",
23897
- effectiveAmount: Number(effectiveRaw) / 10 ** assetInfo.decimals,
23898
- recipient,
23899
- asset
23919
+ preview: {
23920
+ toolName: "send_transfer",
23921
+ effectiveAmount: Number(effectiveRaw) / 10 ** assetInfo.decimals,
23922
+ recipient,
23923
+ asset
23924
+ }
23900
23925
  };
23901
23926
  },
23902
23927
  swap_execute: async (tx, input, ctx) => {
@@ -23916,37 +23941,59 @@ var WRITE_APPENDER_REGISTRY = {
23916
23941
  slippage: input.slippage,
23917
23942
  byAmountIn: input.byAmountIn,
23918
23943
  overlayFee: ctx.overlayFee,
23919
- providers
23944
+ providers,
23945
+ inputCoin: ctx.chainedCoin
23920
23946
  });
23921
- tx.transferObjects([result.coin], ctx.sender);
23947
+ if (!ctx.isOutputConsumed) {
23948
+ tx.transferObjects([result.coin], ctx.sender);
23949
+ }
23922
23950
  return {
23923
- toolName: "swap_execute",
23924
- effectiveAmountIn: result.effectiveAmountIn,
23925
- expectedAmountOut: result.expectedAmountOut,
23926
- route: result.route
23951
+ preview: {
23952
+ toolName: "swap_execute",
23953
+ effectiveAmountIn: result.effectiveAmountIn,
23954
+ expectedAmountOut: result.expectedAmountOut,
23955
+ route: result.route
23956
+ },
23957
+ outputCoin: result.coin
23927
23958
  };
23928
23959
  },
23929
23960
  claim_rewards: async (tx, _input, ctx) => {
23930
23961
  const rewards = await addClaimRewardsToTx(tx, ctx.client, ctx.sender);
23931
- return { toolName: "claim_rewards", rewards };
23962
+ return { preview: { toolName: "claim_rewards", rewards } };
23932
23963
  },
23933
23964
  volo_stake: async (tx, input, ctx) => {
23934
23965
  if (input.amountSui <= 0) {
23935
23966
  throw new T2000Error("INVALID_AMOUNT", "Stake amount must be greater than zero");
23936
23967
  }
23937
23968
  const amountMist = BigInt(Math.floor(input.amountSui * 1e9));
23938
- const result = await addStakeVSuiToTx(tx, ctx.client, ctx.sender, { amountMist });
23939
- tx.transferObjects([result.coin], ctx.sender);
23940
- return { toolName: "volo_stake", effectiveAmountMist: result.effectiveAmountMist };
23969
+ const result = await addStakeVSuiToTx(tx, ctx.client, ctx.sender, {
23970
+ amountMist,
23971
+ inputCoin: ctx.chainedCoin
23972
+ });
23973
+ if (!ctx.isOutputConsumed) {
23974
+ tx.transferObjects([result.coin], ctx.sender);
23975
+ }
23976
+ return {
23977
+ preview: { toolName: "volo_stake", effectiveAmountMist: result.effectiveAmountMist },
23978
+ outputCoin: result.coin
23979
+ };
23941
23980
  },
23942
23981
  volo_unstake: async (tx, input, ctx) => {
23943
23982
  const amountMist = input.amountVSui === "all" ? "all" : BigInt(Math.floor(input.amountVSui * 1e9));
23944
23983
  if (amountMist !== "all" && amountMist <= 0n) {
23945
23984
  throw new T2000Error("INVALID_AMOUNT", "Unstake amount must be greater than zero");
23946
23985
  }
23947
- const result = await addUnstakeVSuiToTx(tx, ctx.client, ctx.sender, { amountMist });
23948
- tx.transferObjects([result.coin], ctx.sender);
23949
- return { toolName: "volo_unstake", effectiveAmountMist: result.effectiveAmountMist };
23986
+ const result = await addUnstakeVSuiToTx(tx, ctx.client, ctx.sender, {
23987
+ amountMist,
23988
+ inputCoin: ctx.chainedCoin
23989
+ });
23990
+ if (!ctx.isOutputConsumed) {
23991
+ tx.transferObjects([result.coin], ctx.sender);
23992
+ }
23993
+ return {
23994
+ preview: { toolName: "volo_unstake", effectiveAmountMist: result.effectiveAmountMist },
23995
+ outputCoin: result.coin
23996
+ };
23950
23997
  }
23951
23998
  };
23952
23999
  function deriveAllowedAddressesFromPtb(tx) {
@@ -23985,15 +24032,38 @@ function base64ToBytes(b64) {
23985
24032
  async function composeTx(opts) {
23986
24033
  const tx = new Transaction();
23987
24034
  tx.setSender(opts.sender);
23988
- const ctx = {
24035
+ const baseCtx = {
23989
24036
  client: opts.client,
23990
24037
  sender: opts.sender,
23991
24038
  sponsoredContext: opts.sponsoredContext ?? false,
23992
24039
  overlayFee: opts.overlayFee,
23993
24040
  feeHooks: opts.feeHooks
23994
24041
  };
24042
+ const consumedSteps = /* @__PURE__ */ new Set();
24043
+ for (let i = 0; i < opts.steps.length; i++) {
24044
+ const step = opts.steps[i];
24045
+ const stepWithChain = step;
24046
+ const idx = stepWithChain.inputCoinFromStep;
24047
+ if (idx === void 0) continue;
24048
+ if (!Number.isInteger(idx) || idx < 0 || idx >= i) {
24049
+ throw new T2000Error(
24050
+ "CHAIN_MODE_INVALID",
24051
+ `Step ${i} (${step.toolName}) has inputCoinFromStep=${idx}, which must be a non-negative integer < ${i} (forward-only references).`
24052
+ );
24053
+ }
24054
+ const producer = opts.steps[idx];
24055
+ if (producer.toolName === "save_deposit" || producer.toolName === "repay_debt" || producer.toolName === "send_transfer" || producer.toolName === "claim_rewards") {
24056
+ throw new T2000Error(
24057
+ "CHAIN_MODE_INVALID",
24058
+ `Step ${i} (${step.toolName}) references step ${idx} (${producer.toolName}) as producer, but '${producer.toolName}' is a terminal consumer that does not produce a chainable coin handle. Allowed producers: withdraw, borrow, swap_execute, volo_stake, volo_unstake.`
24059
+ );
24060
+ }
24061
+ consumedSteps.add(idx);
24062
+ }
24063
+ const priorOutputs = [];
23995
24064
  const previews = [];
23996
- for (const step of opts.steps) {
24065
+ for (let i = 0; i < opts.steps.length; i++) {
24066
+ const step = opts.steps[i];
23997
24067
  const appender = WRITE_APPENDER_REGISTRY[step.toolName];
23998
24068
  if (!appender) {
23999
24069
  throw new T2000Error(
@@ -24001,8 +24071,26 @@ async function composeTx(opts) {
24001
24071
  `No fragment appender registered for tool '${step.toolName}'. Allowed: ${Object.keys(WRITE_APPENDER_REGISTRY).join(", ")}`
24002
24072
  );
24003
24073
  }
24004
- const preview = await appender(tx, step.input, ctx);
24005
- previews.push(preview);
24074
+ const stepWithChain = step;
24075
+ let chainedCoin;
24076
+ if (stepWithChain.inputCoinFromStep !== void 0) {
24077
+ const upstream = priorOutputs[stepWithChain.inputCoinFromStep];
24078
+ if (!upstream) {
24079
+ throw new T2000Error(
24080
+ "CHAIN_MODE_INVALID",
24081
+ `Step ${i} (${step.toolName}) expected a coin handle from step ${stepWithChain.inputCoinFromStep}, but the producer did not return one.`
24082
+ );
24083
+ }
24084
+ chainedCoin = upstream;
24085
+ }
24086
+ const stepCtx = {
24087
+ ...baseCtx,
24088
+ chainedCoin,
24089
+ isOutputConsumed: consumedSteps.has(i)
24090
+ };
24091
+ const result = await appender(tx, step.input, stepCtx);
24092
+ priorOutputs.push(result.outputCoin ?? null);
24093
+ previews.push(result.preview);
24006
24094
  }
24007
24095
  const txKindBytes = await tx.build({ client: opts.client, onlyTransactionKind: true });
24008
24096
  const derivedAllowedAddresses = deriveAllowedAddressesFromPtb(tx);
@@ -24358,4 +24446,4 @@ axios/dist/node/axios.cjs:
24358
24446
  @scure/bip39/index.js:
24359
24447
  (*! scure-bip39 - MIT License (c) 2022 Patricio Palladino, Paul Miller (paulmillr.com) *)
24360
24448
  */
24361
- //# sourceMappingURL=chunk-VZAS6UYO.js.map
24449
+ //# sourceMappingURL=chunk-K6R5CJFK.js.map