@msafe/sui3-sdk 1.0.24 → 1.0.25
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 +100 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +100 -3
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/src/utils/gasFunding.ts +133 -5
package/dist/index.d.cts
CHANGED
|
@@ -349,6 +349,16 @@ declare class InsufficientGasFundsError extends Error {
|
|
|
349
349
|
readonly addressBalance: bigint;
|
|
350
350
|
constructor(gasBudget: bigint, coinBalance: bigint, addressBalance: bigint);
|
|
351
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* Gas coins cannot cover a SUI amount that is split from the gas coin.
|
|
354
|
+
* Happens when the largest 256 coins are still short of amount + gas budget.
|
|
355
|
+
*/
|
|
356
|
+
declare class GasPaymentLimitError extends Error {
|
|
357
|
+
readonly required: bigint;
|
|
358
|
+
readonly covered: bigint;
|
|
359
|
+
readonly coinCount: number;
|
|
360
|
+
constructor(required: bigint, covered: bigint, coinCount: number);
|
|
361
|
+
}
|
|
352
362
|
/**
|
|
353
363
|
* Gas budget must cover pre-rebate costs (computation + storage + overhead).
|
|
354
364
|
* storageRebate is refunded after execution and must not reduce the budget.
|
|
@@ -367,6 +377,15 @@ type PaymentCoinRef = {
|
|
|
367
377
|
* ("gas_budget must be 0 for gasless transactions").
|
|
368
378
|
*/
|
|
369
379
|
declare function pickGasPaymentCoins(coins: PaymentCoinRef[], cover: bigint): PaymentCoinRef[];
|
|
380
|
+
/** SUI that CoinWithBalance intents will split out of the gas coin. */
|
|
381
|
+
declare function gasCoinWithdrawal(tx: Transaction): bigint;
|
|
382
|
+
/**
|
|
383
|
+
* Balance gas payment coins must hold.
|
|
384
|
+
* A SUI withdrawal is taken from the gas coin only when address balance cannot
|
|
385
|
+
* cover that withdrawal by itself. Mysten redeems address balance for the whole
|
|
386
|
+
* amount in that case, and gas payment only has to pay the gas budget.
|
|
387
|
+
*/
|
|
388
|
+
declare function gasPaymentCover(tx: Transaction, addressBalance: bigint, gasBudget: bigint): bigint;
|
|
370
389
|
/** Object IDs a built payload already pins (inputs + gas payment). */
|
|
371
390
|
declare function collectPayloadObjectIds(payload: string | Uint8Array): string[];
|
|
372
391
|
/**
|
|
@@ -658,4 +677,4 @@ declare function getIntentionContent(intention: unknown): unknown;
|
|
|
658
677
|
*/
|
|
659
678
|
declare function transactionFromContent(content: unknown): Transaction;
|
|
660
679
|
|
|
661
|
-
export { AddressBookSDK, COIN_RESERVATION_MAGIC, COIN_TYPE_ARG_REGEX, Coin, CoinHelper, CreateHelper, type CreateMSafeInfo, DEV_API_URL, DEV_SYNCING_URL, ENV_CONFIGS, Formatter, type FutureIntention, type GasFundingMode, type GasFundingResult, type GasObjectReference, HexToUint8Array, type HistorySendTx, type HistoryVote, type IWallet, InfoTypeEnabledDto, InfoTypeKey, InsufficientGasFundsError, LOCAL_API_URL, LOCAL_SYNCING_URL, MAINNET_RPC_URL, MAX_GAS_PAYMENT_OBJECTS, MSafeAccount, MSafeClient, type MSafeConfig, type MSafeConfigOptions, MSafeEnabledDto, MSafeEnv, MSafeGlobals, type NotificationData, type NotificationInfo, NotificationSubscribeDto, NotificationUpdateDto, PREV_API_URL, PROD_API_URL, type Pagination, type PaymentCoinRef, type PendingTx, type PendingVote, type ProposeIntention, type ReceiveTransaction, SUI_COIN, SignatureVerifier, type SimulateDryRunResponse, type SimulationFailedResult, type SimulationOption, type SimulationResult, type SimulationSuccessResult, TESTNET_RPC_URL, Uint8ArrayToHex, addPrefix, collectPayloadObjectIds, collectQueueExcludeObjectIds, computeGasBudget, createCoinReservationRef, estimateGasBudget, getAllCoins, getIntentionContent, getMSafeConfig, getPublicKeyFromChain, httpUrlToGrpcBaseUrl, isCoinReservationDigest, msafeChainToSuiNetwork, parkedPayloadHex, pickGasPaymentCoins, preferClassicGasPayment, prepareGasFunding, selectGasFunding, stringToBuffer, toSuiTransaction, transactionFromContent };
|
|
680
|
+
export { AddressBookSDK, COIN_RESERVATION_MAGIC, COIN_TYPE_ARG_REGEX, Coin, CoinHelper, CreateHelper, type CreateMSafeInfo, DEV_API_URL, DEV_SYNCING_URL, ENV_CONFIGS, Formatter, type FutureIntention, type GasFundingMode, type GasFundingResult, type GasObjectReference, GasPaymentLimitError, HexToUint8Array, type HistorySendTx, type HistoryVote, type IWallet, InfoTypeEnabledDto, InfoTypeKey, InsufficientGasFundsError, LOCAL_API_URL, LOCAL_SYNCING_URL, MAINNET_RPC_URL, MAX_GAS_PAYMENT_OBJECTS, MSafeAccount, MSafeClient, type MSafeConfig, type MSafeConfigOptions, MSafeEnabledDto, MSafeEnv, MSafeGlobals, type NotificationData, type NotificationInfo, NotificationSubscribeDto, NotificationUpdateDto, PREV_API_URL, PROD_API_URL, type Pagination, type PaymentCoinRef, type PendingTx, type PendingVote, type ProposeIntention, type ReceiveTransaction, SUI_COIN, SignatureVerifier, type SimulateDryRunResponse, type SimulationFailedResult, type SimulationOption, type SimulationResult, type SimulationSuccessResult, TESTNET_RPC_URL, Uint8ArrayToHex, addPrefix, collectPayloadObjectIds, collectQueueExcludeObjectIds, computeGasBudget, createCoinReservationRef, estimateGasBudget, gasCoinWithdrawal, gasPaymentCover, getAllCoins, getIntentionContent, getMSafeConfig, getPublicKeyFromChain, httpUrlToGrpcBaseUrl, isCoinReservationDigest, msafeChainToSuiNetwork, parkedPayloadHex, pickGasPaymentCoins, preferClassicGasPayment, prepareGasFunding, selectGasFunding, stringToBuffer, toSuiTransaction, transactionFromContent };
|
package/dist/index.d.ts
CHANGED
|
@@ -349,6 +349,16 @@ declare class InsufficientGasFundsError extends Error {
|
|
|
349
349
|
readonly addressBalance: bigint;
|
|
350
350
|
constructor(gasBudget: bigint, coinBalance: bigint, addressBalance: bigint);
|
|
351
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* Gas coins cannot cover a SUI amount that is split from the gas coin.
|
|
354
|
+
* Happens when the largest 256 coins are still short of amount + gas budget.
|
|
355
|
+
*/
|
|
356
|
+
declare class GasPaymentLimitError extends Error {
|
|
357
|
+
readonly required: bigint;
|
|
358
|
+
readonly covered: bigint;
|
|
359
|
+
readonly coinCount: number;
|
|
360
|
+
constructor(required: bigint, covered: bigint, coinCount: number);
|
|
361
|
+
}
|
|
352
362
|
/**
|
|
353
363
|
* Gas budget must cover pre-rebate costs (computation + storage + overhead).
|
|
354
364
|
* storageRebate is refunded after execution and must not reduce the budget.
|
|
@@ -367,6 +377,15 @@ type PaymentCoinRef = {
|
|
|
367
377
|
* ("gas_budget must be 0 for gasless transactions").
|
|
368
378
|
*/
|
|
369
379
|
declare function pickGasPaymentCoins(coins: PaymentCoinRef[], cover: bigint): PaymentCoinRef[];
|
|
380
|
+
/** SUI that CoinWithBalance intents will split out of the gas coin. */
|
|
381
|
+
declare function gasCoinWithdrawal(tx: Transaction): bigint;
|
|
382
|
+
/**
|
|
383
|
+
* Balance gas payment coins must hold.
|
|
384
|
+
* A SUI withdrawal is taken from the gas coin only when address balance cannot
|
|
385
|
+
* cover that withdrawal by itself. Mysten redeems address balance for the whole
|
|
386
|
+
* amount in that case, and gas payment only has to pay the gas budget.
|
|
387
|
+
*/
|
|
388
|
+
declare function gasPaymentCover(tx: Transaction, addressBalance: bigint, gasBudget: bigint): bigint;
|
|
370
389
|
/** Object IDs a built payload already pins (inputs + gas payment). */
|
|
371
390
|
declare function collectPayloadObjectIds(payload: string | Uint8Array): string[];
|
|
372
391
|
/**
|
|
@@ -658,4 +677,4 @@ declare function getIntentionContent(intention: unknown): unknown;
|
|
|
658
677
|
*/
|
|
659
678
|
declare function transactionFromContent(content: unknown): Transaction;
|
|
660
679
|
|
|
661
|
-
export { AddressBookSDK, COIN_RESERVATION_MAGIC, COIN_TYPE_ARG_REGEX, Coin, CoinHelper, CreateHelper, type CreateMSafeInfo, DEV_API_URL, DEV_SYNCING_URL, ENV_CONFIGS, Formatter, type FutureIntention, type GasFundingMode, type GasFundingResult, type GasObjectReference, HexToUint8Array, type HistorySendTx, type HistoryVote, type IWallet, InfoTypeEnabledDto, InfoTypeKey, InsufficientGasFundsError, LOCAL_API_URL, LOCAL_SYNCING_URL, MAINNET_RPC_URL, MAX_GAS_PAYMENT_OBJECTS, MSafeAccount, MSafeClient, type MSafeConfig, type MSafeConfigOptions, MSafeEnabledDto, MSafeEnv, MSafeGlobals, type NotificationData, type NotificationInfo, NotificationSubscribeDto, NotificationUpdateDto, PREV_API_URL, PROD_API_URL, type Pagination, type PaymentCoinRef, type PendingTx, type PendingVote, type ProposeIntention, type ReceiveTransaction, SUI_COIN, SignatureVerifier, type SimulateDryRunResponse, type SimulationFailedResult, type SimulationOption, type SimulationResult, type SimulationSuccessResult, TESTNET_RPC_URL, Uint8ArrayToHex, addPrefix, collectPayloadObjectIds, collectQueueExcludeObjectIds, computeGasBudget, createCoinReservationRef, estimateGasBudget, getAllCoins, getIntentionContent, getMSafeConfig, getPublicKeyFromChain, httpUrlToGrpcBaseUrl, isCoinReservationDigest, msafeChainToSuiNetwork, parkedPayloadHex, pickGasPaymentCoins, preferClassicGasPayment, prepareGasFunding, selectGasFunding, stringToBuffer, toSuiTransaction, transactionFromContent };
|
|
680
|
+
export { AddressBookSDK, COIN_RESERVATION_MAGIC, COIN_TYPE_ARG_REGEX, Coin, CoinHelper, CreateHelper, type CreateMSafeInfo, DEV_API_URL, DEV_SYNCING_URL, ENV_CONFIGS, Formatter, type FutureIntention, type GasFundingMode, type GasFundingResult, type GasObjectReference, GasPaymentLimitError, HexToUint8Array, type HistorySendTx, type HistoryVote, type IWallet, InfoTypeEnabledDto, InfoTypeKey, InsufficientGasFundsError, LOCAL_API_URL, LOCAL_SYNCING_URL, MAINNET_RPC_URL, MAX_GAS_PAYMENT_OBJECTS, MSafeAccount, MSafeClient, type MSafeConfig, type MSafeConfigOptions, MSafeEnabledDto, MSafeEnv, MSafeGlobals, type NotificationData, type NotificationInfo, NotificationSubscribeDto, NotificationUpdateDto, PREV_API_URL, PROD_API_URL, type Pagination, type PaymentCoinRef, type PendingTx, type PendingVote, type ProposeIntention, type ReceiveTransaction, SUI_COIN, SignatureVerifier, type SimulateDryRunResponse, type SimulationFailedResult, type SimulationOption, type SimulationResult, type SimulationSuccessResult, TESTNET_RPC_URL, Uint8ArrayToHex, addPrefix, collectPayloadObjectIds, collectQueueExcludeObjectIds, computeGasBudget, createCoinReservationRef, estimateGasBudget, gasCoinWithdrawal, gasPaymentCover, getAllCoins, getIntentionContent, getMSafeConfig, getPublicKeyFromChain, httpUrlToGrpcBaseUrl, isCoinReservationDigest, msafeChainToSuiNetwork, parkedPayloadHex, pickGasPaymentCoins, preferClassicGasPayment, prepareGasFunding, selectGasFunding, stringToBuffer, toSuiTransaction, transactionFromContent };
|
package/dist/index.js
CHANGED
|
@@ -418,6 +418,8 @@ async function getAllCoins(input) {
|
|
|
418
418
|
var GAS_SAFE_OVERHEAD = 1000n;
|
|
419
419
|
var MAX_GAS_PAYMENT_OBJECTS = 256;
|
|
420
420
|
var ESTIMATE_GAS_COVER = 1000000000n;
|
|
421
|
+
var MAX_PROBE_GAS_BUDGET = 50000000000n;
|
|
422
|
+
var COIN_WITH_BALANCE_INTENT = "CoinWithBalance";
|
|
421
423
|
var InsufficientGasFundsError = class extends Error {
|
|
422
424
|
gasBudget;
|
|
423
425
|
coinBalance;
|
|
@@ -433,22 +435,57 @@ var InsufficientGasFundsError = class extends Error {
|
|
|
433
435
|
this.addressBalance = addressBalance;
|
|
434
436
|
}
|
|
435
437
|
};
|
|
438
|
+
var GasPaymentLimitError = class extends Error {
|
|
439
|
+
required;
|
|
440
|
+
covered;
|
|
441
|
+
coinCount;
|
|
442
|
+
constructor(required, covered, coinCount) {
|
|
443
|
+
super(gasPaymentLimitMessage(required, covered, coinCount));
|
|
444
|
+
this.name = "GasPaymentLimitError";
|
|
445
|
+
this.required = required;
|
|
446
|
+
this.covered = covered;
|
|
447
|
+
this.coinCount = coinCount;
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
function formatSui(mist) {
|
|
451
|
+
const negative = mist < 0n;
|
|
452
|
+
const value = negative ? -mist : mist;
|
|
453
|
+
const whole = value / 1000000000n;
|
|
454
|
+
const fraction = (value % 1000000000n).toString().padStart(9, "0").replace(/0+$/, "");
|
|
455
|
+
const text = fraction.length > 0 ? `${whole}.${fraction}` : `${whole}`;
|
|
456
|
+
return negative ? `-${text}` : text;
|
|
457
|
+
}
|
|
458
|
+
function gasPaymentLimitMessage(required, covered, coinCount) {
|
|
459
|
+
const requiredSui = formatSui(required);
|
|
460
|
+
const coveredSui = formatSui(covered);
|
|
461
|
+
if (coinCount >= MAX_GAS_PAYMENT_OBJECTS) {
|
|
462
|
+
return `This transfer needs ${requiredSui} SUI from gas coins, but the largest ${MAX_GAS_PAYMENT_OBJECTS} coins only cover ${coveredSui} SUI. Send a smaller amount, or consolidate coins into fewer objects first.`;
|
|
463
|
+
}
|
|
464
|
+
return `This transfer needs ${requiredSui} SUI from gas coins, but the available SUI coin objects only cover ${coveredSui} SUI.`;
|
|
465
|
+
}
|
|
436
466
|
function computeGasBudget(gasUsed, gasPrice) {
|
|
437
467
|
const { computationCost, storageCost } = gasUsed;
|
|
438
468
|
const safeOverhead = GAS_SAFE_OVERHEAD * gasPrice;
|
|
439
469
|
return BigInt(computationCost) + BigInt(storageCost) + safeOverhead;
|
|
440
470
|
}
|
|
471
|
+
function compareBalanceDescending(a, b) {
|
|
472
|
+
if (a.balance === b.balance) {
|
|
473
|
+
return 0;
|
|
474
|
+
}
|
|
475
|
+
return a.balance < b.balance ? 1 : -1;
|
|
476
|
+
}
|
|
441
477
|
function pickGasPaymentCoins(coins, cover) {
|
|
442
478
|
if (cover <= 0n) {
|
|
443
479
|
return [];
|
|
444
480
|
}
|
|
445
|
-
const sorted = [...coins].filter((coin) => coin.balance > 0n).sort(
|
|
481
|
+
const sorted = [...coins].filter((coin) => coin.balance > 0n).sort(compareBalanceDescending);
|
|
446
482
|
const selected = [];
|
|
447
483
|
let sum = 0n;
|
|
448
|
-
for (
|
|
484
|
+
for (let index = 0; index < sorted.length; index += 1) {
|
|
449
485
|
if (selected.length >= MAX_GAS_PAYMENT_OBJECTS) {
|
|
450
486
|
break;
|
|
451
487
|
}
|
|
488
|
+
const coin = sorted[index];
|
|
452
489
|
selected.push(coin);
|
|
453
490
|
sum += coin.balance;
|
|
454
491
|
if (sum >= cover) {
|
|
@@ -457,6 +494,46 @@ function pickGasPaymentCoins(coins, cover) {
|
|
|
457
494
|
}
|
|
458
495
|
return selected;
|
|
459
496
|
}
|
|
497
|
+
function readBigInt(value) {
|
|
498
|
+
if (typeof value === "bigint") {
|
|
499
|
+
return value;
|
|
500
|
+
}
|
|
501
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
502
|
+
return BigInt(Math.trunc(value));
|
|
503
|
+
}
|
|
504
|
+
if (typeof value === "string" && /^-?\d+$/.test(value)) {
|
|
505
|
+
return BigInt(value);
|
|
506
|
+
}
|
|
507
|
+
return 0n;
|
|
508
|
+
}
|
|
509
|
+
function gasCoinWithdrawal(tx) {
|
|
510
|
+
return tx.getData().commands.reduce((sum, command) => {
|
|
511
|
+
if (command.$kind !== "$Intent" || command.$Intent.name !== COIN_WITH_BALANCE_INTENT) {
|
|
512
|
+
return sum;
|
|
513
|
+
}
|
|
514
|
+
const data = command.$Intent.data;
|
|
515
|
+
if (data?.type !== "gas") {
|
|
516
|
+
return sum;
|
|
517
|
+
}
|
|
518
|
+
return sum + readBigInt(data.balance);
|
|
519
|
+
}, 0n);
|
|
520
|
+
}
|
|
521
|
+
function gasPaymentCover(tx, addressBalance, gasBudget) {
|
|
522
|
+
const withdrawal = gasCoinWithdrawal(tx);
|
|
523
|
+
const fromGasCoin = withdrawal > addressBalance ? withdrawal : 0n;
|
|
524
|
+
return gasBudget + fromGasCoin;
|
|
525
|
+
}
|
|
526
|
+
function sumBalances(coins) {
|
|
527
|
+
return coins.reduce((sum, coin) => sum + coin.balance, 0n);
|
|
528
|
+
}
|
|
529
|
+
function pickGasPaymentCoinsForCover(coins, cover) {
|
|
530
|
+
const picked = pickGasPaymentCoins(coins, cover);
|
|
531
|
+
const covered = sumBalances(picked);
|
|
532
|
+
if (cover > 0n && covered < cover) {
|
|
533
|
+
throw new GasPaymentLimitError(cover, covered, picked.length);
|
|
534
|
+
}
|
|
535
|
+
return picked;
|
|
536
|
+
}
|
|
460
537
|
function collectUsedObjectIds(tx) {
|
|
461
538
|
const used = tx.getData().inputs.reduce((acc, input) => {
|
|
462
539
|
const immOrOwned = input.Object?.ImmOrOwnedObject?.objectId;
|
|
@@ -600,6 +677,12 @@ async function selectGasFunding(input) {
|
|
|
600
677
|
if (total < gasBudget) {
|
|
601
678
|
throw new InsufficientGasFundsError(gasBudget, coinBalance, addressBalance);
|
|
602
679
|
}
|
|
680
|
+
const cover = gasPaymentCover(tx, addressBalance, gasBudget);
|
|
681
|
+
if (cover > gasBudget) {
|
|
682
|
+
const picked = pickGasPaymentCoinsForCover(paymentCoins, cover);
|
|
683
|
+
tx.setGasPayment(toObjectRefs(picked));
|
|
684
|
+
return { mode: "classic", gasBudget, coinBalance, addressBalance };
|
|
685
|
+
}
|
|
603
686
|
if (paymentCoins.length > 0 && coinBalance >= gasBudget) {
|
|
604
687
|
tx.setGasPayment(toObjectRefs(pickGasPaymentCoins(paymentCoins, gasBudget)));
|
|
605
688
|
return { mode: "classic", gasBudget, coinBalance, addressBalance };
|
|
@@ -655,7 +738,18 @@ async function estimateGasBudget(input) {
|
|
|
655
738
|
const probe = mustResetGas ? cloneWithClearedGasConfig(tx) : Transaction.from(tx);
|
|
656
739
|
probe.setSender(owner);
|
|
657
740
|
probe.setGasPrice(gasPrice);
|
|
658
|
-
|
|
741
|
+
const fromGasCoin = gasPaymentCover(tx, funding.addressBalance, 0n);
|
|
742
|
+
if (fromGasCoin > 0n) {
|
|
743
|
+
const picked = pickGasPaymentCoins(funding.paymentCoins, fromGasCoin + ESTIMATE_GAS_COVER);
|
|
744
|
+
const covered = sumBalances(picked);
|
|
745
|
+
if (covered <= fromGasCoin) {
|
|
746
|
+
throw new GasPaymentLimitError(fromGasCoin, covered, picked.length);
|
|
747
|
+
}
|
|
748
|
+
probe.setGasPayment(toObjectRefs(picked));
|
|
749
|
+
const remainder = covered - fromGasCoin;
|
|
750
|
+
const probeBudget = remainder > MAX_PROBE_GAS_BUDGET ? MAX_PROBE_GAS_BUDGET : remainder;
|
|
751
|
+
probe.setGasBudget(probeBudget);
|
|
752
|
+
} else if (funding.paymentCoins.length > 0) {
|
|
659
753
|
probe.setGasPayment(toObjectRefs(pickGasPaymentCoins(funding.paymentCoins, ESTIMATE_GAS_COVER)));
|
|
660
754
|
}
|
|
661
755
|
let built;
|
|
@@ -2121,6 +2215,7 @@ export {
|
|
|
2121
2215
|
DEV_SYNCING_URL,
|
|
2122
2216
|
ENV_CONFIGS,
|
|
2123
2217
|
Formatter,
|
|
2218
|
+
GasPaymentLimitError,
|
|
2124
2219
|
HexToUint8Array,
|
|
2125
2220
|
InfoTypeEnabledDto,
|
|
2126
2221
|
InfoTypeKey,
|
|
@@ -2148,6 +2243,8 @@ export {
|
|
|
2148
2243
|
computeGasBudget,
|
|
2149
2244
|
createCoinReservationRef,
|
|
2150
2245
|
estimateGasBudget,
|
|
2246
|
+
gasCoinWithdrawal,
|
|
2247
|
+
gasPaymentCover,
|
|
2151
2248
|
getAllCoins,
|
|
2152
2249
|
getIntentionContent,
|
|
2153
2250
|
getMSafeConfig,
|