aftermath-ts-sdk 3.1.0 → 3.1.1-dev.3618bb3

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.d.ts CHANGED
@@ -14737,7 +14737,21 @@ declare class CoinApi {
14737
14737
  walletAddress: SuiAddress;
14738
14738
  coinType: CoinType;
14739
14739
  }) => Promise<CoinStruct[]>;
14740
- private static coinWithAmountTx;
14740
+ /**
14741
+ * Checks the wallet's TOTAL balance (owned coins + SIP-58 address balance)
14742
+ * covers `coinAmount`, throwing the canonical insufficient-balance error
14743
+ * otherwise. `coinWithBalance` can source from both, so this is the correct
14744
+ * spendability check for the non-sponsored path.
14745
+ */
14746
+ private assertSufficientTotalBalance;
14747
+ /**
14748
+ * Owned-coin arg for the sponsored path: merge the selected coins and split
14749
+ * the amount without touching `tx.gas` (that's the sponsor's coin) and via
14750
+ * raw commands only, since the tx is serialized unbuilt. `coinData` comes
14751
+ * from `fetchCoinsWithAtLeastAmount`, which guarantees it covers
14752
+ * `coinAmount`.
14753
+ */
14754
+ private static sponsoredCoinWithAmountTx;
14741
14755
  }
14742
14756
 
14743
14757
  declare class DcaApi {
package/dist/index.js CHANGED
@@ -15980,14 +15980,17 @@ var init_wallet = __esm({
15980
15980
  });
15981
15981
 
15982
15982
  // src/packages/coin/api/coinApi.ts
15983
- var _CoinApi, CoinApi;
15983
+ import {
15984
+ coinWithBalance
15985
+ } from "@mysten/sui/transactions";
15986
+ var MAX_COIN_FETCH_PAGES, _CoinApi, CoinApi;
15984
15987
  var init_coinApi = __esm({
15985
15988
  "src/packages/coin/api/coinApi.ts"() {
15986
15989
  "use strict";
15987
15990
  init_transactionsApiHelpers();
15988
15991
  init_grpcCasting();
15989
15992
  init_helpers();
15990
- init_coin();
15993
+ MAX_COIN_FETCH_PAGES = 50;
15991
15994
  _CoinApi = class _CoinApi {
15992
15995
  // =========================================================================
15993
15996
  // Constructor
@@ -16000,74 +16003,63 @@ var init_coinApi = __esm({
16000
16003
  this.fetchCoinWithAmountTx = async (inputs) => {
16001
16004
  const { tx, walletAddress, coinType, coinAmount, isSponsoredTx } = inputs;
16002
16005
  tx.setSender(walletAddress);
16003
- const coinData = await this.fetchCoinsWithAtLeastAmount(inputs);
16004
- return _CoinApi.coinWithAmountTx({
16005
- tx,
16006
- coinData,
16007
- coinAmount,
16008
- coinType,
16009
- isSponsoredTx
16010
- });
16006
+ if (isSponsoredTx) {
16007
+ const coinData = await this.fetchCoinsWithAtLeastAmount(inputs);
16008
+ return _CoinApi.sponsoredCoinWithAmountTx({
16009
+ tx,
16010
+ coinData,
16011
+ coinAmount,
16012
+ coinType
16013
+ });
16014
+ }
16015
+ await this.assertSufficientTotalBalance(inputs);
16016
+ return coinWithBalance({ type: coinType, balance: coinAmount })(tx);
16011
16017
  };
16012
16018
  this.fetchCoinsWithAmountTx = async (inputs) => {
16013
- const { tx, walletAddress, coinTypes, coinAmounts, isSponsoredTx } = inputs;
16014
- tx.setSender(walletAddress);
16015
- const allCoinsData = await Promise.all(
16016
- coinTypes.map(
16017
- async (coinType, index) => this.fetchCoinsWithAtLeastAmount({
16019
+ const { coinTypes, coinAmounts } = inputs;
16020
+ const coinArgs = [];
16021
+ for (const [index, coinType] of coinTypes.entries()) {
16022
+ coinArgs.push(
16023
+ await this.fetchCoinWithAmountTx({
16018
16024
  ...inputs,
16019
- coinAmount: coinAmounts[index],
16020
- coinType
16025
+ coinType,
16026
+ coinAmount: coinAmounts[index]
16021
16027
  })
16022
- )
16023
- );
16024
- let coinArgs = [];
16025
- for (const [index, coinData] of allCoinsData.entries()) {
16026
- const coinArg = _CoinApi.coinWithAmountTx({
16027
- tx,
16028
- coinData,
16029
- coinAmount: coinAmounts[index],
16030
- coinType: coinTypes[index],
16031
- isSponsoredTx
16032
- });
16033
- coinArgs = [...coinArgs, coinArg];
16028
+ );
16034
16029
  }
16035
16030
  return coinArgs;
16036
16031
  };
16037
16032
  this.fetchCoinsWithAtLeastAmount = async (inputs) => {
16038
- let allCoinData = [];
16033
+ const allCoinData = [];
16039
16034
  let cursor;
16040
- do {
16035
+ for (let page = 0; page < MAX_COIN_FETCH_PAGES; page++) {
16041
16036
  const paginatedCoins = await this.api.client.listCoins({
16042
16037
  coinType: inputs.coinType,
16043
16038
  owner: inputs.walletAddress,
16044
16039
  cursor
16045
16040
  });
16046
- const coinData = paginatedCoins.objects.map(
16047
- GrpcCasting.coinStructFromGrpcCoin
16041
+ allCoinData.push(
16042
+ ...paginatedCoins.objects.map(GrpcCasting.coinStructFromGrpcCoin)
16048
16043
  );
16049
- allCoinData = [...allCoinData, ...coinData];
16050
- if (paginatedCoins.objects.length === 0 || !paginatedCoins.hasNextPage || !paginatedCoins.cursor) {
16051
- allCoinData.sort(
16052
- (b, a) => Number(BigInt(a.balance) - BigInt(b.balance))
16053
- );
16054
- const coinDatas = [];
16055
- let sum = BigInt(0);
16056
- for (const coinData2 of allCoinData) {
16057
- coinDatas.push(coinData2);
16058
- sum += BigInt(coinData2.balance);
16059
- if (sum >= inputs.coinAmount) {
16060
- return coinDatas;
16061
- }
16044
+ allCoinData.sort((b, a) => Number(BigInt(a.balance) - BigInt(b.balance)));
16045
+ const selectedCoins = [];
16046
+ let sum = BigInt(0);
16047
+ for (const coinData of allCoinData) {
16048
+ selectedCoins.push(coinData);
16049
+ sum += BigInt(coinData.balance);
16050
+ if (sum >= inputs.coinAmount) {
16051
+ return selectedCoins;
16062
16052
  }
16053
+ }
16054
+ if (paginatedCoins.objects.length === 0 || !paginatedCoins.hasNextPage || !paginatedCoins.cursor) {
16063
16055
  throw new Error("wallet does not have coins of sufficient balance");
16064
16056
  }
16065
16057
  cursor = paginatedCoins.cursor;
16066
- } while (true);
16058
+ }
16059
+ throw new Error("wallet balance is spread across too many coin objects");
16067
16060
  };
16068
- // fetchCoinsUntilAmountReachedOrEnd
16069
16061
  this.fetchAllCoins = async (inputs) => {
16070
- let allCoinData = [];
16062
+ const allCoinData = [];
16071
16063
  let cursor;
16072
16064
  do {
16073
16065
  const paginatedCoins = await this.api.client.listCoins({
@@ -16075,71 +16067,66 @@ var init_coinApi = __esm({
16075
16067
  owner: inputs.walletAddress,
16076
16068
  cursor
16077
16069
  });
16078
- const coinData = paginatedCoins.objects.map(
16079
- GrpcCasting.coinStructFromGrpcCoin
16070
+ allCoinData.push(
16071
+ ...paginatedCoins.objects.map(GrpcCasting.coinStructFromGrpcCoin)
16080
16072
  );
16081
- allCoinData = [...allCoinData, ...coinData];
16082
- if (paginatedCoins.objects.length === 0 || !paginatedCoins.hasNextPage || !paginatedCoins.cursor) {
16083
- return allCoinData.sort(
16084
- (b, a) => Number(BigInt(b.coinObjectId) - BigInt(a.coinObjectId))
16085
- );
16086
- }
16087
- cursor = paginatedCoins.cursor;
16088
- } while (true);
16073
+ cursor = paginatedCoins.objects.length > 0 && paginatedCoins.hasNextPage && paginatedCoins.cursor ? paginatedCoins.cursor : void 0;
16074
+ } while (cursor !== void 0);
16075
+ return allCoinData.sort(
16076
+ (b, a) => Number(BigInt(b.coinObjectId) - BigInt(a.coinObjectId))
16077
+ );
16078
+ };
16079
+ // =========================================================================
16080
+ // Private Helpers
16081
+ // =========================================================================
16082
+ /**
16083
+ * Checks the wallet's TOTAL balance (owned coins + SIP-58 address balance)
16084
+ * covers `coinAmount`, throwing the canonical insufficient-balance error
16085
+ * otherwise. `coinWithBalance` can source from both, so this is the correct
16086
+ * spendability check for the non-sponsored path.
16087
+ */
16088
+ this.assertSufficientTotalBalance = async (inputs) => {
16089
+ const { balance } = await this.api.client.getBalance({
16090
+ owner: inputs.walletAddress,
16091
+ coinType: Helpers.stripLeadingZeroesFromType(inputs.coinType)
16092
+ });
16093
+ if (BigInt(balance.balance) < inputs.coinAmount) {
16094
+ throw new Error("wallet does not have coins of sufficient balance");
16095
+ }
16089
16096
  };
16090
16097
  }
16091
16098
  };
16092
16099
  // =========================================================================
16093
16100
  // Private Static Methods
16094
16101
  // =========================================================================
16095
- _CoinApi.coinWithAmountTx = (inputs) => {
16096
- const { tx, coinData, coinAmount, coinType, isSponsoredTx } = inputs;
16097
- if (coinData.length <= 0) {
16098
- throw new Error("wallet does not have coins of sufficient balance");
16099
- }
16100
- const isSuiCoin = Coin.isSuiCoin(coinData[0].coinType);
16101
- const totalCoinBalance = Helpers.sumBigInt(
16102
- coinData.map((data) => BigInt(data.balance))
16103
- );
16104
- if (totalCoinBalance < coinAmount) {
16105
- throw new Error("wallet does not have coins of sufficient balance");
16106
- }
16107
- if (!isSponsoredTx && isSuiCoin) {
16108
- tx.setGasPayment(
16109
- coinData.map((obj) => {
16110
- return {
16111
- ...obj,
16112
- objectId: obj.coinObjectId
16113
- };
16114
- })
16115
- );
16116
- return tx.splitCoins(tx.gas, [coinAmount]);
16117
- }
16102
+ /**
16103
+ * Owned-coin arg for the sponsored path: merge the selected coins and split
16104
+ * the amount without touching `tx.gas` (that's the sponsor's coin) and via
16105
+ * raw commands only, since the tx is serialized unbuilt. `coinData` comes
16106
+ * from `fetchCoinsWithAtLeastAmount`, which guarantees it covers
16107
+ * `coinAmount`.
16108
+ */
16109
+ _CoinApi.sponsoredCoinWithAmountTx = (inputs) => {
16110
+ const { tx, coinData, coinAmount, coinType } = inputs;
16118
16111
  const coinObjectIds = coinData.map((data) => data.coinObjectId);
16119
16112
  const mergedCoinObjectId = coinObjectIds[0];
16120
16113
  if (coinObjectIds.length > 1) {
16121
- if (isSponsoredTx) {
16122
- tx.add({
16123
- $kind: "MergeCoins",
16124
- MergeCoins: {
16125
- destination: tx.object(mergedCoinObjectId),
16126
- sources: [
16127
- ...coinObjectIds.slice(1).map((coinId) => tx.object(coinId))
16128
- ]
16129
- }
16130
- });
16131
- } else {
16132
- tx.mergeCoins(tx.object(mergedCoinObjectId), [
16133
- ...coinObjectIds.slice(1).map((coinId) => tx.object(coinId))
16134
- ]);
16135
- }
16114
+ tx.add({
16115
+ $kind: "MergeCoins",
16116
+ MergeCoins: {
16117
+ destination: tx.object(mergedCoinObjectId),
16118
+ sources: [
16119
+ ...coinObjectIds.slice(1).map((coinId) => tx.object(coinId))
16120
+ ]
16121
+ }
16122
+ });
16136
16123
  }
16137
- return isSponsoredTx ? TransactionsApiHelpers.splitCoinTx({
16124
+ return TransactionsApiHelpers.splitCoinTx({
16138
16125
  tx,
16139
16126
  coinId: mergedCoinObjectId,
16140
16127
  amount: coinAmount,
16141
16128
  coinType
16142
- }) : tx.splitCoins(mergedCoinObjectId, [coinAmount]);
16129
+ });
16143
16130
  };
16144
16131
  CoinApi = _CoinApi;
16145
16132
  }