@msafe/sui3-sdk 1.0.23 → 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 +125 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -1
- package/dist/index.d.ts +35 -1
- package/dist/index.js +125 -5
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/src/utils/gasFunding.ts +172 -7
package/dist/index.d.cts
CHANGED
|
@@ -334,6 +334,8 @@ declare class InvitationSDK {
|
|
|
334
334
|
updateMSafeStatus(msafeAddress: string, status: UserMSafeStatus): Promise<void>;
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
+
/** Protocol cap: a transaction may smash at most this many gas payment objects. */
|
|
338
|
+
declare const MAX_GAS_PAYMENT_OBJECTS = 256;
|
|
337
339
|
type GasFundingMode = 'classic' | 'addressBalance' | 'mixedTopUp';
|
|
338
340
|
interface GasFundingResult {
|
|
339
341
|
mode: GasFundingMode;
|
|
@@ -347,11 +349,43 @@ declare class InsufficientGasFundsError extends Error {
|
|
|
347
349
|
readonly addressBalance: bigint;
|
|
348
350
|
constructor(gasBudget: bigint, coinBalance: bigint, addressBalance: bigint);
|
|
349
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
|
+
}
|
|
350
362
|
/**
|
|
351
363
|
* Gas budget must cover pre-rebate costs (computation + storage + overhead).
|
|
352
364
|
* storageRebate is refunded after execution and must not reduce the budget.
|
|
353
365
|
*/
|
|
354
366
|
declare function computeGasBudget(gasUsed: Pick<SuiClientTypes.GasCostSummary, 'computationCost' | 'storageCost'>, gasPrice: bigint): bigint;
|
|
367
|
+
type PaymentCoinRef = {
|
|
368
|
+
objectId: string;
|
|
369
|
+
version: string;
|
|
370
|
+
digest: string;
|
|
371
|
+
balance: bigint;
|
|
372
|
+
};
|
|
373
|
+
/**
|
|
374
|
+
* Pick the fewest large SUI coins that cover `cover`, capped at 256.
|
|
375
|
+
* Never attach every owned coin — accounts with hundreds of SUI objects
|
|
376
|
+
* exceed max_gas_payment_objects and trip gasless estimate
|
|
377
|
+
* ("gas_budget must be 0 for gasless transactions").
|
|
378
|
+
*/
|
|
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;
|
|
355
389
|
/** Object IDs a built payload already pins (inputs + gas payment). */
|
|
356
390
|
declare function collectPayloadObjectIds(payload: string | Uint8Array): string[];
|
|
357
391
|
/**
|
|
@@ -643,4 +677,4 @@ declare function getIntentionContent(intention: unknown): unknown;
|
|
|
643
677
|
*/
|
|
644
678
|
declare function transactionFromContent(content: unknown): Transaction;
|
|
645
679
|
|
|
646
|
-
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, MSafeAccount, MSafeClient, type MSafeConfig, type MSafeConfigOptions, MSafeEnabledDto, MSafeEnv, MSafeGlobals, type NotificationData, type NotificationInfo, NotificationSubscribeDto, NotificationUpdateDto, PREV_API_URL, PROD_API_URL, type Pagination, 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, 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
|
@@ -334,6 +334,8 @@ declare class InvitationSDK {
|
|
|
334
334
|
updateMSafeStatus(msafeAddress: string, status: UserMSafeStatus): Promise<void>;
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
+
/** Protocol cap: a transaction may smash at most this many gas payment objects. */
|
|
338
|
+
declare const MAX_GAS_PAYMENT_OBJECTS = 256;
|
|
337
339
|
type GasFundingMode = 'classic' | 'addressBalance' | 'mixedTopUp';
|
|
338
340
|
interface GasFundingResult {
|
|
339
341
|
mode: GasFundingMode;
|
|
@@ -347,11 +349,43 @@ declare class InsufficientGasFundsError extends Error {
|
|
|
347
349
|
readonly addressBalance: bigint;
|
|
348
350
|
constructor(gasBudget: bigint, coinBalance: bigint, addressBalance: bigint);
|
|
349
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
|
+
}
|
|
350
362
|
/**
|
|
351
363
|
* Gas budget must cover pre-rebate costs (computation + storage + overhead).
|
|
352
364
|
* storageRebate is refunded after execution and must not reduce the budget.
|
|
353
365
|
*/
|
|
354
366
|
declare function computeGasBudget(gasUsed: Pick<SuiClientTypes.GasCostSummary, 'computationCost' | 'storageCost'>, gasPrice: bigint): bigint;
|
|
367
|
+
type PaymentCoinRef = {
|
|
368
|
+
objectId: string;
|
|
369
|
+
version: string;
|
|
370
|
+
digest: string;
|
|
371
|
+
balance: bigint;
|
|
372
|
+
};
|
|
373
|
+
/**
|
|
374
|
+
* Pick the fewest large SUI coins that cover `cover`, capped at 256.
|
|
375
|
+
* Never attach every owned coin — accounts with hundreds of SUI objects
|
|
376
|
+
* exceed max_gas_payment_objects and trip gasless estimate
|
|
377
|
+
* ("gas_budget must be 0 for gasless transactions").
|
|
378
|
+
*/
|
|
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;
|
|
355
389
|
/** Object IDs a built payload already pins (inputs + gas payment). */
|
|
356
390
|
declare function collectPayloadObjectIds(payload: string | Uint8Array): string[];
|
|
357
391
|
/**
|
|
@@ -643,4 +677,4 @@ declare function getIntentionContent(intention: unknown): unknown;
|
|
|
643
677
|
*/
|
|
644
678
|
declare function transactionFromContent(content: unknown): Transaction;
|
|
645
679
|
|
|
646
|
-
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, MSafeAccount, MSafeClient, type MSafeConfig, type MSafeConfigOptions, MSafeEnabledDto, MSafeEnv, MSafeGlobals, type NotificationData, type NotificationInfo, NotificationSubscribeDto, NotificationUpdateDto, PREV_API_URL, PROD_API_URL, type Pagination, 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, 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
|
@@ -416,6 +416,10 @@ async function getAllCoins(input) {
|
|
|
416
416
|
|
|
417
417
|
// src/utils/gasFunding.ts
|
|
418
418
|
var GAS_SAFE_OVERHEAD = 1000n;
|
|
419
|
+
var MAX_GAS_PAYMENT_OBJECTS = 256;
|
|
420
|
+
var ESTIMATE_GAS_COVER = 1000000000n;
|
|
421
|
+
var MAX_PROBE_GAS_BUDGET = 50000000000n;
|
|
422
|
+
var COIN_WITH_BALANCE_INTENT = "CoinWithBalance";
|
|
419
423
|
var InsufficientGasFundsError = class extends Error {
|
|
420
424
|
gasBudget;
|
|
421
425
|
coinBalance;
|
|
@@ -431,11 +435,105 @@ var InsufficientGasFundsError = class extends Error {
|
|
|
431
435
|
this.addressBalance = addressBalance;
|
|
432
436
|
}
|
|
433
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
|
+
}
|
|
434
466
|
function computeGasBudget(gasUsed, gasPrice) {
|
|
435
467
|
const { computationCost, storageCost } = gasUsed;
|
|
436
468
|
const safeOverhead = GAS_SAFE_OVERHEAD * gasPrice;
|
|
437
469
|
return BigInt(computationCost) + BigInt(storageCost) + safeOverhead;
|
|
438
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
|
+
}
|
|
477
|
+
function pickGasPaymentCoins(coins, cover) {
|
|
478
|
+
if (cover <= 0n) {
|
|
479
|
+
return [];
|
|
480
|
+
}
|
|
481
|
+
const sorted = [...coins].filter((coin) => coin.balance > 0n).sort(compareBalanceDescending);
|
|
482
|
+
const selected = [];
|
|
483
|
+
let sum = 0n;
|
|
484
|
+
for (let index = 0; index < sorted.length; index += 1) {
|
|
485
|
+
if (selected.length >= MAX_GAS_PAYMENT_OBJECTS) {
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
488
|
+
const coin = sorted[index];
|
|
489
|
+
selected.push(coin);
|
|
490
|
+
sum += coin.balance;
|
|
491
|
+
if (sum >= cover) {
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return selected;
|
|
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
|
+
}
|
|
439
537
|
function collectUsedObjectIds(tx) {
|
|
440
538
|
const used = tx.getData().inputs.reduce((acc, input) => {
|
|
441
539
|
const immOrOwned = input.Object?.ImmOrOwnedObject?.objectId;
|
|
@@ -579,8 +677,14 @@ async function selectGasFunding(input) {
|
|
|
579
677
|
if (total < gasBudget) {
|
|
580
678
|
throw new InsufficientGasFundsError(gasBudget, coinBalance, addressBalance);
|
|
581
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
|
+
}
|
|
582
686
|
if (paymentCoins.length > 0 && coinBalance >= gasBudget) {
|
|
583
|
-
tx.setGasPayment(toObjectRefs(paymentCoins));
|
|
687
|
+
tx.setGasPayment(toObjectRefs(pickGasPaymentCoins(paymentCoins, gasBudget)));
|
|
584
688
|
return { mode: "classic", gasBudget, coinBalance, addressBalance };
|
|
585
689
|
}
|
|
586
690
|
if (paymentCoins.length > 0 && total >= gasBudget) {
|
|
@@ -589,7 +693,7 @@ async function selectGasFunding(input) {
|
|
|
589
693
|
tx,
|
|
590
694
|
suiClient,
|
|
591
695
|
owner,
|
|
592
|
-
paymentCoins,
|
|
696
|
+
paymentCoins: pickGasPaymentCoins(paymentCoins, 1n),
|
|
593
697
|
topUpAmount
|
|
594
698
|
});
|
|
595
699
|
return { mode: "mixedTopUp", gasBudget, coinBalance, addressBalance };
|
|
@@ -634,8 +738,19 @@ async function estimateGasBudget(input) {
|
|
|
634
738
|
const probe = mustResetGas ? cloneWithClearedGasConfig(tx) : Transaction.from(tx);
|
|
635
739
|
probe.setSender(owner);
|
|
636
740
|
probe.setGasPrice(gasPrice);
|
|
637
|
-
|
|
638
|
-
|
|
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) {
|
|
753
|
+
probe.setGasPayment(toObjectRefs(pickGasPaymentCoins(funding.paymentCoins, ESTIMATE_GAS_COVER)));
|
|
639
754
|
}
|
|
640
755
|
let built;
|
|
641
756
|
try {
|
|
@@ -710,7 +825,7 @@ async function preferClassicGasPayment(input) {
|
|
|
710
825
|
if (funding.paymentCoins.length === 0) {
|
|
711
826
|
return false;
|
|
712
827
|
}
|
|
713
|
-
tx.setGasPayment(toObjectRefs(funding.paymentCoins));
|
|
828
|
+
tx.setGasPayment(toObjectRefs(pickGasPaymentCoins(funding.paymentCoins, ESTIMATE_GAS_COVER)));
|
|
714
829
|
return true;
|
|
715
830
|
}
|
|
716
831
|
|
|
@@ -2100,6 +2215,7 @@ export {
|
|
|
2100
2215
|
DEV_SYNCING_URL,
|
|
2101
2216
|
ENV_CONFIGS,
|
|
2102
2217
|
Formatter,
|
|
2218
|
+
GasPaymentLimitError,
|
|
2103
2219
|
HexToUint8Array,
|
|
2104
2220
|
InfoTypeEnabledDto,
|
|
2105
2221
|
InfoTypeKey,
|
|
@@ -2107,6 +2223,7 @@ export {
|
|
|
2107
2223
|
LOCAL_API_URL,
|
|
2108
2224
|
LOCAL_SYNCING_URL,
|
|
2109
2225
|
MAINNET_RPC_URL,
|
|
2226
|
+
MAX_GAS_PAYMENT_OBJECTS,
|
|
2110
2227
|
MSafeAccount,
|
|
2111
2228
|
MSafeClient,
|
|
2112
2229
|
MSafeEnabledDto,
|
|
@@ -2126,6 +2243,8 @@ export {
|
|
|
2126
2243
|
computeGasBudget,
|
|
2127
2244
|
createCoinReservationRef,
|
|
2128
2245
|
estimateGasBudget,
|
|
2246
|
+
gasCoinWithdrawal,
|
|
2247
|
+
gasPaymentCover,
|
|
2129
2248
|
getAllCoins,
|
|
2130
2249
|
getIntentionContent,
|
|
2131
2250
|
getMSafeConfig,
|
|
@@ -2134,6 +2253,7 @@ export {
|
|
|
2134
2253
|
isCoinReservationDigest,
|
|
2135
2254
|
msafeChainToSuiNetwork,
|
|
2136
2255
|
parkedPayloadHex,
|
|
2256
|
+
pickGasPaymentCoins,
|
|
2137
2257
|
preferClassicGasPayment,
|
|
2138
2258
|
prepareGasFunding,
|
|
2139
2259
|
selectGasFunding,
|