@metamask-previews/transaction-pay-controller 30.1.0-preview-32b6da31c → 30.1.0-preview-eefc6963e
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 +2 -0
- package/dist/strategy/relay/relay-quotes.d.ts.map +1 -1
- package/dist/strategy/relay/relay-quotes.js +16 -191
- package/dist/strategy/relay/relay-quotes.js.map +1 -1
- package/dist/utils/post-quote.d.ts +19 -0
- package/dist/utils/post-quote.d.ts.map +1 -0
- package/dist/utils/post-quote.js +76 -0
- package/dist/utils/post-quote.js.map +1 -0
- package/dist/utils/quote-gas.d.ts +36 -0
- package/dist/utils/quote-gas.d.ts.map +1 -1
- package/dist/utils/quote-gas.js +93 -1
- package/dist/utils/quote-gas.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
10
10
|
### Changed
|
|
11
11
|
|
|
12
12
|
- Bump `@metamask/transaction-controller` from `^72.2.0` to `^72.2.1` ([#10817](https://github.com/MetaMask/core/pull/10817))
|
|
13
|
+
- Bump `@metamask/accounts-controller` from `^40.0.0` to `^40.1.0` ([#10851](https://github.com/MetaMask/core/pull/10851))
|
|
14
|
+
- Bump `@metamask/keyring-controller` from `^28.1.0` to `^28.2.0` ([#10851](https://github.com/MetaMask/core/pull/10851))
|
|
13
15
|
|
|
14
16
|
## [30.1.0]
|
|
15
17
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay-quotes.d.ts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAGV,2BAA2B,EAG3B,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AA0CxB,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"relay-quotes.d.ts","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAGV,2BAA2B,EAG3B,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AA0CxB,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,YAAY,CAAC;AASpB;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC,CAsE5C"}
|
|
@@ -7,11 +7,12 @@ import { ARBITRUM_USDC_ADDRESS, CHAIN_ID_ARBITRUM, CHAIN_ID_HYPERCORE, CHAIN_ID_
|
|
|
7
7
|
import { TransactionPayStrategy } from '../../index.js';
|
|
8
8
|
import { projectLogger } from '../../logger.js';
|
|
9
9
|
import { getFiatValueFromUsd } from '../../utils/amounts.js';
|
|
10
|
-
import {
|
|
10
|
+
import { getRelayOriginGasOverhead, getSlippage, getStablecoins, isAtomicMaxEnabled, isEIP7702Chain, isRelayExecuteEnabled, } from '../../utils/feature-flags.js';
|
|
11
11
|
import { GasPaymentMode, resolveGasPayment, resolveGasStationCost, } from '../../utils/gas-payment.js';
|
|
12
12
|
import { calculateGasCost } from '../../utils/gas.js';
|
|
13
13
|
import { getPolymarketDepositWalletOverrides, getPredictWithdrawFeeTokenAccount, getPredictWithdrawSafeAddress, } from '../../utils/polymarket/withdraw.js';
|
|
14
|
-
import {
|
|
14
|
+
import { reservePostQuoteGas } from '../../utils/post-quote.js';
|
|
15
|
+
import { estimateSourceGas } from '../../utils/quote-gas.js';
|
|
15
16
|
import { resolveNonAtomicRecipient } from '../../utils/second-leg.js';
|
|
16
17
|
import { getNativeToken, getTokenFiatRate, normalizeTokenAddress, TokenAddressTarget, } from '../../utils/token.js';
|
|
17
18
|
import { getQuotePricing } from '../../utils/trade-type.js';
|
|
@@ -22,11 +23,6 @@ import { fetchRelayQuote } from './relay-api.js';
|
|
|
22
23
|
import { getRelayMaxQuote, isSubsidizedAtomicMaxQuote, throwAtomicPromotionFailed, } from './relay-max.js';
|
|
23
24
|
import { validateRelayQuotes } from './relay-validation.js';
|
|
24
25
|
const log = createModuleLogger(projectLogger, 'relay-strategy');
|
|
25
|
-
// Buffer applied to the gas cost when reserving native tokens for gas in
|
|
26
|
-
// post-quote flows, accounting for gas limit re-estimation variance.
|
|
27
|
-
const POST_QUOTE_GAS_BUFFER = 1.1;
|
|
28
|
-
// Hardcoded gas allowance for the prepended payment override transaction(s).
|
|
29
|
-
const PAYMENT_OVERRIDE_GAS = 75_000;
|
|
30
26
|
const ZERO_AMOUNT = { fiat: '0', human: '0', raw: '0', usd: '0' };
|
|
31
27
|
/**
|
|
32
28
|
* Fetches Relay quotes.
|
|
@@ -106,56 +102,10 @@ async function getQuoteWithPostQuoteGasHandling(request, fullRequest) {
|
|
|
106
102
|
if (phase1Quote.original.metamask?.isExecute) {
|
|
107
103
|
return phase1Quote;
|
|
108
104
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// the native gas token (gas comes from the same pool as the swap value).
|
|
113
|
-
const isSourceNative = request.sourceTokenAddress.toLowerCase() ===
|
|
114
|
-
getNativeToken(request.sourceChainId).toLowerCase() ||
|
|
115
|
-
request.sourceTokenAddress.toLowerCase() ===
|
|
116
|
-
NATIVE_TOKEN_ADDRESS.toLowerCase();
|
|
117
|
-
if (!phase1Quote.fees.isSourceGasFeeToken && !isSourceNative) {
|
|
118
|
-
return phase1Quote;
|
|
119
|
-
}
|
|
120
|
-
const gasCostRaw = new BigNumber(phase1Quote.fees.sourceNetwork.max.raw)
|
|
121
|
-
.multipliedBy(POST_QUOTE_GAS_BUFFER)
|
|
122
|
-
.integerValue(BigNumber.ROUND_UP);
|
|
123
|
-
const existingHeadroom = new BigNumber(request.sourceBalanceRaw).minus(request.sourceTokenAmount);
|
|
124
|
-
if (existingHeadroom.isGreaterThanOrEqualTo(gasCostRaw)) {
|
|
125
|
-
log('Sufficient existing balance for gas, skipping subtraction', {
|
|
126
|
-
existingHeadroom: existingHeadroom.toString(10),
|
|
127
|
-
gasCostRaw: gasCostRaw.toString(10),
|
|
128
|
-
});
|
|
129
|
-
return phase1Quote;
|
|
130
|
-
}
|
|
131
|
-
const adjustedSourceAmount = new BigNumber(request.sourceTokenAmount)
|
|
132
|
-
.minus(gasCostRaw)
|
|
133
|
-
.integerValue(BigNumber.ROUND_DOWN);
|
|
134
|
-
log('Subtracting gas from source for post-quote two-call', {
|
|
135
|
-
originalSourceAmount: request.sourceTokenAmount,
|
|
136
|
-
gasCostRaw,
|
|
137
|
-
adjustedSourceAmount: adjustedSourceAmount.toString(10),
|
|
105
|
+
return await reservePostQuoteGas({
|
|
106
|
+
quote: phase1Quote,
|
|
107
|
+
requote: (adjustedRequest) => getSingleQuote(adjustedRequest, fullRequest),
|
|
138
108
|
});
|
|
139
|
-
if (!adjustedSourceAmount.isGreaterThan(0)) {
|
|
140
|
-
log('Insufficient balance after gas subtraction for post-quote, using phase 1');
|
|
141
|
-
return phase1Quote;
|
|
142
|
-
}
|
|
143
|
-
try {
|
|
144
|
-
const phase2Quote = await getSingleQuote({
|
|
145
|
-
...request,
|
|
146
|
-
sourceTokenAmount: adjustedSourceAmount.toFixed(0, BigNumber.ROUND_DOWN),
|
|
147
|
-
}, fullRequest);
|
|
148
|
-
if (phase1Quote.fees.isSourceGasFeeToken &&
|
|
149
|
-
!phase2Quote.fees.isSourceGasFeeToken) {
|
|
150
|
-
log('Phase 2 lost gas fee token eligibility, falling back to phase 1');
|
|
151
|
-
return phase1Quote;
|
|
152
|
-
}
|
|
153
|
-
return phase2Quote;
|
|
154
|
-
}
|
|
155
|
-
catch (error) {
|
|
156
|
-
log('Phase 2 quote failed, falling back to phase 1', { error });
|
|
157
|
-
return phase1Quote;
|
|
158
|
-
}
|
|
159
109
|
}
|
|
160
110
|
/**
|
|
161
111
|
* Fetches a single Relay quote.
|
|
@@ -578,22 +528,13 @@ async function calculateSourceNetworkCost(quote, messenger, request, transaction
|
|
|
578
528
|
// gas estimation. For swap-only routes, fall back to the relay params'
|
|
579
529
|
// EOA `from` so simulation succeeds.
|
|
580
530
|
const fromOverride = getPredictWithdrawSafeAddress(request, transaction, hasRelayDepositStep(quote.steps));
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
const allGasParams = originalTxGasParams
|
|
589
|
-
? [originalTxGasParams, ...relayParams]
|
|
590
|
-
: relayParams;
|
|
591
|
-
const gasResult = await calculateSourceNetworkGasLimit(allGasParams, messenger, fromOverride);
|
|
592
|
-
// When the original tx was NOT included in gas estimation (no gas params
|
|
593
|
-
// available), fall back to the legacy prepend-after-the-fact approach.
|
|
594
|
-
const { gasLimits, is7702, totalGasEstimate, totalGasLimit } = originalTxGasParams
|
|
595
|
-
? gasResult
|
|
596
|
-
: combinePrependedGas(gasResult, request, transaction);
|
|
531
|
+
const { gasLimits, is7702, totalGasEstimate, totalGasLimit } = await estimateSourceGas({
|
|
532
|
+
fromOverride,
|
|
533
|
+
messenger,
|
|
534
|
+
request,
|
|
535
|
+
transaction,
|
|
536
|
+
transactions: relayParams.map(toQuoteGasTransaction),
|
|
537
|
+
});
|
|
597
538
|
log('Gas limit', {
|
|
598
539
|
is7702,
|
|
599
540
|
totalGasEstimate,
|
|
@@ -659,132 +600,16 @@ async function calculateSourceNetworkCost(quote, messenger, request, transaction
|
|
|
659
600
|
is7702,
|
|
660
601
|
};
|
|
661
602
|
}
|
|
662
|
-
|
|
663
|
-
* Calculate the total gas limit for the source network.
|
|
664
|
-
*
|
|
665
|
-
* @param params - Array of relay transaction parameters.
|
|
666
|
-
* @param messenger - Controller messenger.
|
|
667
|
-
* @param fromOverride - Optional address to use as `from` in gas estimation
|
|
668
|
-
* instead of the address in the relay params. Used in predict withdraw flows
|
|
669
|
-
* to estimate with the proxy/Safe address that holds the source token balance.
|
|
670
|
-
* @returns Total gas estimates and per-transaction gas limits.
|
|
671
|
-
*/
|
|
672
|
-
async function calculateSourceNetworkGasLimit(params, messenger, fromOverride) {
|
|
673
|
-
const transactions = params.map((singleParams) => toRelayQuoteGasTransaction(singleParams, fromOverride));
|
|
674
|
-
const relayGasResult = await estimateQuoteGasLimits({
|
|
675
|
-
fallbackGas: getFeatureFlags(messenger).relayFallbackGas,
|
|
676
|
-
fallbackOnSimulationFailure: true,
|
|
677
|
-
messenger,
|
|
678
|
-
transactions,
|
|
679
|
-
});
|
|
680
|
-
return {
|
|
681
|
-
gasLimits: relayGasResult.gasLimits.map((gasLimit) => gasLimit.max),
|
|
682
|
-
is7702: relayGasResult.is7702,
|
|
683
|
-
totalGasEstimate: relayGasResult.totalGasEstimate,
|
|
684
|
-
totalGasLimit: relayGasResult.totalGasLimit,
|
|
685
|
-
};
|
|
686
|
-
}
|
|
687
|
-
function toRelayQuoteGasTransaction(singleParams, fromOverride) {
|
|
603
|
+
function toQuoteGasTransaction(singleParams) {
|
|
688
604
|
return {
|
|
689
605
|
chainId: toHex(singleParams.chainId),
|
|
690
606
|
data: singleParams.data,
|
|
691
|
-
from:
|
|
692
|
-
gas:
|
|
607
|
+
from: singleParams.from,
|
|
608
|
+
gas: singleParams.gas,
|
|
693
609
|
to: singleParams.to,
|
|
694
610
|
value: singleParams.value ?? '0',
|
|
695
611
|
};
|
|
696
612
|
}
|
|
697
|
-
function getOriginalTxGasParams(request, transaction) {
|
|
698
|
-
if (!request.isPostQuote) {
|
|
699
|
-
return undefined;
|
|
700
|
-
}
|
|
701
|
-
const { txParams } = transaction;
|
|
702
|
-
const to = txParams.to;
|
|
703
|
-
if (!to) {
|
|
704
|
-
return undefined;
|
|
705
|
-
}
|
|
706
|
-
const hasAccountOverride = request.from.toLowerCase() !== txParams.from.toLowerCase();
|
|
707
|
-
if (hasAccountOverride) {
|
|
708
|
-
return undefined;
|
|
709
|
-
}
|
|
710
|
-
const nestedGas = transaction.nestedTransactions?.find((tx) => tx.gas)?.gas;
|
|
711
|
-
const gas = nestedGas ?? txParams.gas;
|
|
712
|
-
return {
|
|
713
|
-
chainId: Number(transaction.chainId),
|
|
714
|
-
data: txParams.data ?? '0x',
|
|
715
|
-
from: txParams.from,
|
|
716
|
-
gas: gas ? String(gas) : undefined,
|
|
717
|
-
maxFeePerGas: '0',
|
|
718
|
-
maxPriorityFeePerGas: '0',
|
|
719
|
-
to,
|
|
720
|
-
value: txParams.value ?? '0',
|
|
721
|
-
};
|
|
722
|
-
}
|
|
723
|
-
function combinePrependedGas(relayOnlyGas, request, transaction) {
|
|
724
|
-
const gas = request.isPostQuote
|
|
725
|
-
? combinePostQuoteGas(relayOnlyGas, transaction)
|
|
726
|
-
: relayOnlyGas;
|
|
727
|
-
return request.paymentOverride ? addPaymentOverrideGas(gas) : gas;
|
|
728
|
-
}
|
|
729
|
-
/**
|
|
730
|
-
* Combine the original transaction's gas with relay gas for post-quote flows.
|
|
731
|
-
*
|
|
732
|
-
* Prefers gas from `nestedTransactions` (preserves the caller-provided value)
|
|
733
|
-
* since TransactionController may re-estimate `txParams.gas` during batch
|
|
734
|
-
* creation.
|
|
735
|
-
*
|
|
736
|
-
* @param relayGas - Gas estimates from relay transactions.
|
|
737
|
-
* @param relayGas.totalGasEstimate - Estimated gas total.
|
|
738
|
-
* @param relayGas.totalGasLimit - Maximum gas total.
|
|
739
|
-
* @param relayGas.gasLimits - Per-transaction gas limits.
|
|
740
|
-
* @param relayGas.is7702 - Whether the relay gas came from a combined 7702 batch estimate.
|
|
741
|
-
* @param transaction - Original transaction metadata.
|
|
742
|
-
* @returns Combined gas estimates including the original transaction.
|
|
743
|
-
*/
|
|
744
|
-
function combinePostQuoteGas(relayGas, transaction) {
|
|
745
|
-
const nestedGas = transaction.nestedTransactions?.find((tx) => tx.gas)?.gas;
|
|
746
|
-
const rawGas = nestedGas ?? transaction.txParams.gas;
|
|
747
|
-
const originalTxGas = rawGas ? new BigNumber(rawGas).toNumber() : undefined;
|
|
748
|
-
if (originalTxGas === undefined) {
|
|
749
|
-
return relayGas;
|
|
750
|
-
}
|
|
751
|
-
let { gasLimits } = relayGas;
|
|
752
|
-
if (relayGas.is7702) {
|
|
753
|
-
// Combined 7702 gas limit — add the original tx gas so the batch
|
|
754
|
-
// keeps using a single 7702 limit.
|
|
755
|
-
gasLimits = [gasLimits[0] + originalTxGas];
|
|
756
|
-
}
|
|
757
|
-
else {
|
|
758
|
-
// Multiple individual gas limits — prepend the original tx gas
|
|
759
|
-
// so the list order matches relay-submit's transaction order.
|
|
760
|
-
gasLimits = [originalTxGas, ...gasLimits];
|
|
761
|
-
}
|
|
762
|
-
const totalGasEstimate = relayGas.totalGasEstimate + originalTxGas;
|
|
763
|
-
const totalGasLimit = relayGas.totalGasLimit + originalTxGas;
|
|
764
|
-
log('Combined original tx gas with relay gas', {
|
|
765
|
-
originalTxGas,
|
|
766
|
-
is7702: relayGas.is7702,
|
|
767
|
-
gasLimits,
|
|
768
|
-
totalGasLimit,
|
|
769
|
-
});
|
|
770
|
-
return {
|
|
771
|
-
totalGasEstimate,
|
|
772
|
-
totalGasLimit,
|
|
773
|
-
gasLimits,
|
|
774
|
-
is7702: relayGas.is7702,
|
|
775
|
-
};
|
|
776
|
-
}
|
|
777
|
-
function addPaymentOverrideGas(relayGas) {
|
|
778
|
-
const gasLimits = relayGas.is7702
|
|
779
|
-
? [relayGas.gasLimits[0] + PAYMENT_OVERRIDE_GAS]
|
|
780
|
-
: [PAYMENT_OVERRIDE_GAS, ...relayGas.gasLimits];
|
|
781
|
-
return {
|
|
782
|
-
totalGasEstimate: relayGas.totalGasEstimate + PAYMENT_OVERRIDE_GAS,
|
|
783
|
-
totalGasLimit: relayGas.totalGasLimit + PAYMENT_OVERRIDE_GAS,
|
|
784
|
-
gasLimits,
|
|
785
|
-
is7702: relayGas.is7702,
|
|
786
|
-
};
|
|
787
|
-
}
|
|
788
613
|
/**
|
|
789
614
|
* Calculate the provider fee for a Relay quote.
|
|
790
615
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay-quotes.js","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable require-atomic-updates */\n\nimport { Interface } from '@ethersproject/abi';\nimport { toHex } from '@metamask/controller-utils';\nimport type {\n AuthorizationList,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n ARBITRUM_USDC_ADDRESS,\n CHAIN_ID_ARBITRUM,\n CHAIN_ID_HYPERCORE,\n CHAIN_ID_POLYGON,\n HYPERCORE_USDC_ADDRESS,\n HYPERCORE_USDC_DECIMALS,\n NATIVE_TOKEN_ADDRESS,\n PERPS_DEPOSIT_TYPES,\n USDC_DECIMALS,\n PaymentOverride,\n} from '../../constants.js';\nimport { TransactionPayStrategy } from '../../index.js';\nimport { projectLogger } from '../../logger.js';\nimport type {\n Amount,\n FiatRates,\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types.js';\nimport { getFiatValueFromUsd } from '../../utils/amounts.js';\nimport {\n getFeatureFlags,\n getRelayOriginGasOverhead,\n getSlippage,\n getStablecoins,\n isAtomicMaxEnabled,\n isEIP7702Chain,\n isRelayExecuteEnabled,\n} from '../../utils/feature-flags.js';\nimport {\n GasPaymentMode,\n resolveGasPayment,\n resolveGasStationCost,\n} from '../../utils/gas-payment.js';\nimport { calculateGasCost } from '../../utils/gas.js';\nimport {\n getPolymarketDepositWalletOverrides,\n getPredictWithdrawFeeTokenAccount,\n getPredictWithdrawSafeAddress,\n} from '../../utils/polymarket/withdraw.js';\nimport { estimateQuoteGasLimits } from '../../utils/quote-gas.js';\nimport type { QuoteGasTransaction } from '../../utils/quote-gas.js';\nimport { resolveNonAtomicRecipient } from '../../utils/second-leg.js';\nimport {\n getNativeToken,\n getTokenFiatRate,\n normalizeTokenAddress,\n TokenAddressTarget,\n} from '../../utils/token.js';\nimport { getQuotePricing } from '../../utils/trade-type.js';\nimport { TOKEN_TRANSFER_FOUR_BYTE } from './constants.js';\nimport { hasRelayDepositStep } from './deposit-step.js';\nimport { applyHyperliquidActivationFee } from './hyperliquid-activation.js';\nimport { fetchRelayQuote } from './relay-api.js';\nimport {\n getRelayMaxQuote,\n isSubsidizedAtomicMaxQuote,\n throwAtomicPromotionFailed,\n} from './relay-max.js';\nimport { validateRelayQuotes } from './relay-validation.js';\nimport type {\n RelayQuote,\n RelayQuoteMetamask,\n RelayQuoteRequest,\n RelayTransactionStep,\n} from './types.js';\n\nconst log = createModuleLogger(projectLogger, 'relay-strategy');\n\n// Buffer applied to the gas cost when reserving native tokens for gas in\n// post-quote flows, accounting for gas limit re-estimation variance.\nconst POST_QUOTE_GAS_BUFFER = 1.1;\n\n// Hardcoded gas allowance for the prepended payment override transaction(s).\nconst PAYMENT_OVERRIDE_GAS = 75_000;\nconst ZERO_AMOUNT = { fiat: '0', human: '0', raw: '0', usd: '0' };\n\ntype RelayQuoteRequestDraft = Omit<RelayQuoteRequest, 'amount' | 'tradeType'> &\n Partial<Pick<RelayQuoteRequest, 'amount'>>;\ntype RelayStepData = RelayTransactionStep['items'][0]['data'];\n\ntype RelayGasResult = {\n totalGasEstimate: number;\n totalGasLimit: number;\n gasLimits: number[];\n is7702: boolean;\n};\n\n/**\n * Fetches Relay quotes.\n *\n * @param request - Request object.\n * @returns Array of quotes.\n */\nexport async function getRelayQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>[]> {\n const { requests } = request;\n\n log('Fetching quotes', requests);\n\n try {\n const normalizedRequests = await Promise.all(\n requests\n .filter((singleRequest) => {\n const hasTargetMinimum = singleRequest.targetAmountMinimum !== '0';\n const isPostQuote = Boolean(singleRequest.isPostQuote);\n const isExactInputRequest =\n Boolean(singleRequest.isMaxAmount) &&\n new BigNumber(singleRequest.sourceTokenAmount).gt(0);\n\n return hasTargetMinimum || isPostQuote || isExactInputRequest;\n })\n .map((singleRequest) =>\n normalizeRequest(singleRequest, request.transaction),\n )\n .map((normalizedRequest) =>\n applyHyperliquidActivationFee(\n normalizedRequest,\n request.messenger,\n request.transaction,\n request.signal,\n ),\n ),\n );\n\n log('Normalized requests', normalizedRequests);\n\n const quotes = await Promise.all(\n normalizedRequests.map((singleRequest) =>\n getQuoteWithMaxAmountHandling(singleRequest, request),\n ),\n );\n\n const atomicMaxQuotes = quotes.filter(isSubsidizedAtomicMaxQuote);\n const otherQuotes = quotes.filter(\n (quote) => !isSubsidizedAtomicMaxQuote(quote),\n );\n\n if (otherQuotes.length > 0) {\n await validateRelayQuotes({\n messenger: request.messenger,\n quotes: otherQuotes,\n signal: request.signal,\n transaction: request.transaction,\n });\n }\n\n if (atomicMaxQuotes.length > 0) {\n try {\n await validateRelayQuotes({\n messenger: request.messenger,\n quotes: atomicMaxQuotes,\n signal: request.signal,\n transaction: request.transaction,\n });\n } catch (error) {\n throwAtomicPromotionFailed(error);\n }\n }\n\n return quotes;\n } catch (error) {\n log('Error fetching quotes', { error });\n throw error;\n }\n}\n\nasync function getQuoteWithMaxAmountHandling(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const { isMaxAmount } = request;\n\n if (!isMaxAmount) {\n return getQuoteWithPostQuoteGasHandling(request, fullRequest);\n }\n\n return getRelayMaxQuote(request, fullRequest, getSingleQuote);\n}\n\n/**\n * For post-quote flows, fetch an initial quote to compute gas cost in source\n * token, then re-quote with the source amount reduced by the gas cost.\n * This ensures Relay reserves enough for the gas fee token payment.\n *\n * For non-post-quote flows, just returns a single quote.\n *\n * @param request - Quote request.\n * @param fullRequest - Full request context.\n * @returns The final quote (phase 2 for post-quote, or phase 1 for normal).\n */\nasync function getQuoteWithPostQuoteGasHandling(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const phase1Quote = await getSingleQuote(request, fullRequest);\n\n if (!request.isPostQuote) {\n return phase1Quote;\n }\n\n if (phase1Quote.original.metamask?.isExecute) {\n return phase1Quote;\n }\n\n // Gas must be subtracted from the source amount when the user's balance\n // is fully committed to the swap. This applies when gas is paid via an\n // ERC-20 fee token (isSourceGasFeeToken) OR when the source itself is\n // the native gas token (gas comes from the same pool as the swap value).\n const isSourceNative =\n request.sourceTokenAddress.toLowerCase() ===\n getNativeToken(request.sourceChainId).toLowerCase() ||\n request.sourceTokenAddress.toLowerCase() ===\n NATIVE_TOKEN_ADDRESS.toLowerCase();\n\n if (!phase1Quote.fees.isSourceGasFeeToken && !isSourceNative) {\n return phase1Quote;\n }\n\n const gasCostRaw = new BigNumber(phase1Quote.fees.sourceNetwork.max.raw)\n .multipliedBy(POST_QUOTE_GAS_BUFFER)\n .integerValue(BigNumber.ROUND_UP);\n\n const existingHeadroom = new BigNumber(request.sourceBalanceRaw).minus(\n request.sourceTokenAmount,\n );\n\n if (existingHeadroom.isGreaterThanOrEqualTo(gasCostRaw)) {\n log('Sufficient existing balance for gas, skipping subtraction', {\n existingHeadroom: existingHeadroom.toString(10),\n gasCostRaw: gasCostRaw.toString(10),\n });\n return phase1Quote;\n }\n\n const adjustedSourceAmount = new BigNumber(request.sourceTokenAmount)\n .minus(gasCostRaw)\n .integerValue(BigNumber.ROUND_DOWN);\n\n log('Subtracting gas from source for post-quote two-call', {\n originalSourceAmount: request.sourceTokenAmount,\n gasCostRaw,\n adjustedSourceAmount: adjustedSourceAmount.toString(10),\n });\n\n if (!adjustedSourceAmount.isGreaterThan(0)) {\n log(\n 'Insufficient balance after gas subtraction for post-quote, using phase 1',\n );\n return phase1Quote;\n }\n\n try {\n const phase2Quote = await getSingleQuote(\n {\n ...request,\n sourceTokenAmount: adjustedSourceAmount.toFixed(\n 0,\n BigNumber.ROUND_DOWN,\n ),\n },\n fullRequest,\n );\n\n if (\n phase1Quote.fees.isSourceGasFeeToken &&\n !phase2Quote.fees.isSourceGasFeeToken\n ) {\n log('Phase 2 lost gas fee token eligibility, falling back to phase 1');\n return phase1Quote;\n }\n\n return phase2Quote;\n } catch (error) {\n log('Phase 2 quote failed, falling back to phase 1', { error });\n return phase1Quote;\n }\n}\n\n/**\n * Fetches a single Relay quote.\n *\n * @param request - Quote request.\n * @param fullRequest - Full quotes request.\n * @returns Single quote.\n */\nasync function getSingleQuote(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const {\n accountSupports7702: supports7702,\n messenger,\n signal,\n transaction,\n } = fullRequest;\n\n const {\n from,\n sourceChainId,\n sourceTokenAddress,\n sourceTokenAmount,\n targetAmountMinimum,\n targetChainId,\n targetTokenAddress,\n } = request;\n\n const slippageDecimal = getSlippage(\n messenger,\n sourceChainId,\n sourceTokenAddress,\n );\n\n const slippageTolerance = new BigNumber(slippageDecimal * 100 * 100).toFixed(\n 0,\n );\n\n try {\n const useExecute =\n supports7702 &&\n isRelayExecuteEnabled(messenger) &&\n isEIP7702Chain(messenger, sourceChainId);\n\n const nonAtomicRecipient = await resolveNonAtomicRecipient(\n transaction,\n request,\n messenger,\n );\n\n const effectiveRequest = nonAtomicRecipient\n ? { ...request, recipient: nonAtomicRecipient }\n : request;\n\n const body: RelayQuoteRequestDraft = {\n destinationChainId: Number(targetChainId),\n destinationCurrency: targetTokenAddress,\n originChainId: Number(sourceChainId),\n originCurrency: sourceTokenAddress,\n ...(useExecute\n ? {\n originGasOverhead: getRelayOriginGasOverhead(messenger),\n metamask: { executeVersion: 2 },\n }\n : {}),\n recipient: effectiveRequest.recipient ?? from,\n slippageTolerance,\n user: from,\n };\n\n if (effectiveRequest.isPolymarketDepositWallet) {\n const overrides = await getPolymarketDepositWalletOverrides(\n from,\n messenger,\n );\n const { depositWallet } = overrides;\n\n body.originCurrency = overrides.sourceTokenAddress;\n body.user = depositWallet;\n body.refundTo = depositWallet;\n body.useDepositAddress = true;\n body.strict = true;\n }\n\n const isAtomic = effectiveRequest.atomic !== false;\n\n const processedTransactions = await processTransactions(\n transaction,\n effectiveRequest,\n body,\n messenger,\n );\n\n if (\n !processedTransactions &&\n isAtomic &&\n effectiveRequest.isPostQuote &&\n effectiveRequest.paymentOverride === PaymentOverride.MoneyAccount\n ) {\n await processMoneyAccountPostQuote(\n transaction,\n effectiveRequest,\n body,\n messenger,\n );\n } else if (!processedTransactions && effectiveRequest.refundTo) {\n // For post-quote flows, honour the caller-specified refund address so that\n // failed Relay transactions refund to the correct account (e.g. the Predict\n // Safe proxy) rather than defaulting to the EOA.\n body.refundTo = effectiveRequest.refundTo;\n }\n\n const pricing = getQuotePricing({\n hasCalls: Boolean(body.txs?.length),\n sourceTokenAmount,\n targetAmountMinimum,\n transaction,\n });\n\n const finalBody: RelayQuoteRequest = {\n ...body,\n // A step that bundled its own calls has already pinned the amount those\n // calls consume, so it wins over the derived amount.\n amount: body.amount ?? pricing.amount,\n tradeType: pricing.tradeType,\n };\n\n log('Request body', finalBody);\n\n const quote = await fetchRelayQuote(messenger, finalBody, signal);\n\n log('Fetched relay quote', quote);\n\n return await normalizeQuote(quote, effectiveRequest, fullRequest);\n } catch (error) {\n log('Error fetching relay quote', error);\n throw error;\n }\n}\n\nfunction normalizeAuthorizationList(\n authorizationList: AuthorizationList | undefined,\n): RelayQuoteRequest['authorizationList'] {\n return authorizationList?.map((a) => ({\n ...a,\n chainId: Number(a.chainId),\n nonce: Number(a.nonce),\n r: a.r as Hex,\n s: a.s as Hex,\n yParity: Number(a.yParity),\n }));\n}\n\n/**\n * Add tranasction data to request body if needed.\n *\n * @param transaction - Transaction metadata.\n * @param request - Quote request.\n * @param requestBody - Request body to populate.\n * @param messenger - Controller messenger.\n * @returns `true` when the transaction was embedded in the quote; `false` when\n * skipped so the caller can route to an alternate handler.\n */\nasync function processTransactions(\n transaction: TransactionMeta,\n request: QuoteRequest,\n requestBody: RelayQuoteRequestDraft,\n messenger: TransactionPayControllerMessenger,\n): Promise<boolean> {\n // Skip when skipProcessTransactions (defaulting to isPostQuote) is set — the\n // original transaction is submitted separately, not embedded in the quote.\n // Skip Polymarket deposit wallet flows — the source is already a bridged\n // token transfer, not a contract call to embed. Skip non-atomic flows — the\n // second leg is submitted after Relay settlement.\n if (\n (request.skipProcessTransactions ?? request.isPostQuote) === true ||\n request.isPolymarketDepositWallet === true ||\n request.atomic === false\n ) {\n return false;\n }\n\n const { nestedTransactions, txParams } = transaction;\n const { isMaxAmount, targetChainId } = request;\n const data = txParams?.data as Hex | undefined;\n\n const singleData =\n nestedTransactions?.length === 1 ? nestedTransactions[0].data : data;\n\n const isHypercore = targetChainId === CHAIN_ID_HYPERCORE;\n\n const isTokenTransfer =\n !isHypercore && Boolean(singleData?.startsWith(TOKEN_TRANSFER_FOUR_BYTE));\n\n if (isTokenTransfer) {\n requestBody.recipient = getTransferRecipient(singleData as Hex);\n\n log('Updating recipient as token transfer', requestBody.recipient);\n }\n\n const hasNoData = singleData === undefined || singleData === '0x';\n const skipDelegation = hasNoData || isTokenTransfer || isHypercore;\n\n if (skipDelegation) {\n log('Skipping delegation as token transfer or Hypercore deposit');\n return true;\n }\n\n // Eligible atomic max requests carry a destination amount, so the calls\n // below use EXACT_OUTPUT rather than the usual max EXACT_INPUT quote.\n if (\n isMaxAmount &&\n (request.isPostQuote === true ||\n !isAtomicMaxEnabled(messenger, transaction))\n ) {\n throw new Error('Max amount quotes do not support included transactions');\n }\n\n const delegation = await messenger.call(\n 'TransactionPayController:getDelegationTransaction',\n { transaction },\n );\n\n requestBody.authorizationList = normalizeAuthorizationList(\n delegation.authorizationList,\n );\n\n const tokenTransferData = nestedTransactions?.find((nestedTx) =>\n nestedTx.data?.startsWith(TOKEN_TRANSFER_FOUR_BYTE),\n )?.data;\n\n // If the transactions include a token transfer, change the recipient\n // so any extra dust is also sent to the same address, rather than back to the user.\n if (tokenTransferData) {\n requestBody.recipient = getTransferRecipient(tokenTransferData);\n requestBody.refundTo = request.from;\n }\n\n requestBody.txs = [\n {\n to: request.targetTokenAddress,\n data: buildTokenTransferData(\n transaction.txParams.from as Hex,\n request.targetAmountMinimum,\n ),\n value: '0x0',\n },\n {\n to: delegation.to,\n data: delegation.data,\n value: delegation.value,\n },\n ];\n\n return true;\n}\n\nasync function processMoneyAccountPostQuote(\n transaction: TransactionMeta,\n request: QuoteRequest,\n requestBody: RelayQuoteRequestDraft,\n messenger: TransactionPayControllerMessenger,\n): Promise<void> {\n const { transactionData: transactionDataList } = messenger.call(\n 'TransactionPayController:getState',\n );\n\n const transactionData = transactionDataList[transaction.id];\n const amountHuman = transactionData?.tokens?.[0]?.amountHuman ?? '0';\n\n const {\n calls: overrideCalls,\n recipient,\n authorizationList,\n } = await messenger.call('TransactionPayController:getPaymentOverrideData', {\n amount: amountHuman,\n transaction,\n transactionData,\n });\n\n if (!overrideCalls.length) {\n log('No payment override calls for money account post-quote');\n return;\n }\n\n const fundingRecipient = recipient ?? request.from;\n const rawAmount = transactionData?.tokens?.[0]?.amountRaw ?? '0';\n\n requestBody.authorizationList = normalizeAuthorizationList(authorizationList);\n requestBody.amount = rawAmount;\n requestBody.txs = [\n {\n to: request.targetTokenAddress,\n data: buildTokenTransferData(fundingRecipient, rawAmount),\n value: '0x0',\n },\n ...overrideCalls.map((call) => ({\n to: call.to as Hex,\n data: call.data as Hex,\n value: (call.value as Hex) ?? '0x0',\n })),\n ];\n\n log('Added money account deposit calls to quote body', {\n callCount: overrideCalls.length,\n });\n}\n\n/**\n * Normalizes requests for Relay.\n *\n * @param request - Quote request to normalize.\n * @param transaction - Parent transaction metadata, used to gate\n * Hyperliquid-specific rewrites on transaction type.\n * @returns Normalized request.\n */\nfunction normalizeRequest(\n request: QuoteRequest,\n transaction: TransactionMeta,\n): QuoteRequest {\n const newRequest = {\n ...request,\n };\n\n const isPerpsDeposit =\n transaction.type !== undefined &&\n PERPS_DEPOSIT_TYPES.includes(transaction.type);\n\n const isHyperliquidDeposit =\n isPerpsDeposit &&\n !request.isPostQuote &&\n request.targetChainId === CHAIN_ID_ARBITRUM &&\n request.targetTokenAddress.toLowerCase() ===\n ARBITRUM_USDC_ADDRESS.toLowerCase();\n\n newRequest.sourceTokenAddress = normalizeTokenAddress(\n newRequest.sourceTokenAddress,\n newRequest.sourceChainId,\n TokenAddressTarget.Relay,\n );\n newRequest.targetTokenAddress = normalizeTokenAddress(\n newRequest.targetTokenAddress,\n newRequest.targetChainId,\n TokenAddressTarget.Relay,\n );\n\n if (isHyperliquidDeposit) {\n newRequest.targetChainId = CHAIN_ID_HYPERCORE;\n newRequest.targetTokenAddress = HYPERCORE_USDC_ADDRESS;\n newRequest.targetAmountMinimum = new BigNumber(request.targetAmountMinimum)\n .shiftedBy(HYPERCORE_USDC_DECIMALS - USDC_DECIMALS)\n .toString(10);\n\n log('Converting Arbitrum Hyperliquid deposit to direct deposit', {\n originalRequest: request,\n normalizedRequest: newRequest,\n });\n }\n\n // HyperLiquid withdrawal: source is HyperCore Perps USDC, not Arbitrum.\n if (request.isHyperliquidSource) {\n newRequest.sourceChainId = CHAIN_ID_HYPERCORE;\n newRequest.sourceTokenAddress = HYPERCORE_USDC_ADDRESS;\n\n if (newRequest.sourceTokenAmount) {\n newRequest.sourceTokenAmount = new BigNumber(newRequest.sourceTokenAmount)\n .shiftedBy(HYPERCORE_USDC_DECIMALS - USDC_DECIMALS)\n .toString(10);\n }\n }\n\n return newRequest;\n}\n\n/**\n * Normalizes a Relay quote into a TransactionPayQuote.\n *\n * @param quote - Relay quote.\n * @param request - Original quote request.\n * @param fullRequest - Full quotes request.\n * @returns Normalized quote.\n */\nasync function normalizeQuote(\n quote: RelayQuote,\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const { messenger } = fullRequest;\n const { details } = quote;\n const { currencyIn, currencyOut } = details;\n\n const { usdToFiatRate } = getFiatRates(messenger, request);\n\n const dust = getFiatValueFromUsd(\n calculateDustUsd(quote, request),\n usdToFiatRate,\n );\n\n const subsidizedFeeUsd = getSubsidizedFeeAmountUsd(messenger, quote);\n\n const appFeeUsd = new BigNumber(quote.fees?.app?.amountUsd ?? '0');\n const metaMaskFee = getFiatValueFromUsd(appFeeUsd, usdToFiatRate);\n\n // Subtract app fee from provider fee since totalImpact.usd already includes\n // it. The relay provider fee is forced to zero when the quote is subsidized,\n // but any reserved HyperLiquid activation fee is withheld from the source\n // send regardless, so it must always be surfaced in the provider fee.\n const activationFeeUsd = new BigNumber(\n request.hyperliquidActivationFeeUsd ?? '0',\n );\n const providerFeeUsd = subsidizedFeeUsd.gt(0)\n ? activationFeeUsd\n : calculateProviderFee(quote).minus(appFeeUsd).plus(activationFeeUsd);\n const provider = getFiatValueFromUsd(providerFeeUsd, usdToFiatRate);\n\n const {\n gasLimits,\n is7702,\n isGasFeeToken: isSourceGasFeeToken,\n ...sourceNetwork\n } = await calculateSourceNetworkCost(\n quote,\n messenger,\n request,\n fullRequest.transaction,\n fullRequest.accountSupports7702,\n );\n\n const targetNetwork = {\n usd: '0',\n fiat: '0',\n };\n\n const sourceAmount: Amount = {\n human: currencyIn.amountFormatted,\n raw: currencyIn.amount,\n ...getFiatValueFromUsd(new BigNumber(currencyIn.amountUsd), usdToFiatRate),\n };\n\n const isTargetStablecoin = isStablecoin(\n messenger,\n request.targetChainId,\n request.targetTokenAddress,\n );\n\n const targetAmountUsd = isTargetStablecoin\n ? new BigNumber(currencyOut.amountFormatted)\n : new BigNumber(currencyOut.amountUsd);\n\n const targetAmount = getFiatValueFromUsd(targetAmountUsd, usdToFiatRate);\n\n const metamask: RelayQuoteMetamask = {\n ...quote.metamask,\n gasLimits: is7702 ? [gasLimits[0]] : gasLimits,\n is7702,\n };\n\n return {\n dust,\n estimatedDuration: details.timeEstimate,\n fees: {\n isSourceGasFeeToken,\n metaMask: metaMaskFee,\n provider,\n sourceNetwork,\n targetNetwork,\n },\n isInputBased: quote.request.tradeType === 'EXACT_INPUT',\n original: {\n ...quote,\n metamask,\n },\n request,\n sourceAmount,\n targetAmount,\n strategy: TransactionPayStrategy.Relay,\n };\n}\n\n/**\n * Calculate dust USD value.\n *\n * @param quote - Relay quote.\n * @param request - Quote request.\n * @returns Dust value in USD and fiat.\n */\nfunction calculateDustUsd(quote: RelayQuote, request: QuoteRequest): BigNumber {\n const { currencyOut } = quote.details;\n const { amountUsd, amountFormatted, minimumAmount } = currencyOut;\n const { decimals: targetDecimals } = currencyOut.currency;\n\n const targetUsdRate = new BigNumber(amountUsd).dividedBy(amountFormatted);\n\n const dustRaw = BigNumber.maximum(\n new BigNumber(minimumAmount).minus(request.targetAmountMinimum),\n 0,\n );\n\n return dustRaw.shiftedBy(-targetDecimals).multipliedBy(targetUsdRate);\n}\n\n/**\n * Calculates USD to fiat rate.\n *\n * @param messenger - Controller messenger.\n * @param request - Quote request.\n * @returns USD to fiat rate.\n */\nfunction getFiatRates(\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n): {\n sourceFiatRate: FiatRates;\n usdToFiatRate: BigNumber;\n} {\n // For HyperLiquid source, the normalized chain/token (HyperCore + Perps USDC)\n // won't have a fiat rate entry. Use Arbitrum USDC instead since Perps USDC\n // is pegged 1:1.\n const sourceChainId = request.isHyperliquidSource\n ? CHAIN_ID_ARBITRUM\n : request.sourceChainId;\n const sourceTokenAddress = request.isHyperliquidSource\n ? ARBITRUM_USDC_ADDRESS\n : request.sourceTokenAddress;\n\n const finalSourceTokenAddress =\n sourceChainId === CHAIN_ID_POLYGON &&\n sourceTokenAddress === NATIVE_TOKEN_ADDRESS\n ? getNativeToken(sourceChainId)\n : sourceTokenAddress;\n\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n finalSourceTokenAddress,\n sourceChainId,\n );\n\n if (!sourceFiatRate) {\n throw new Error('Source token fiat rate not found');\n }\n\n const usdToFiatRate = new BigNumber(sourceFiatRate.fiatRate).dividedBy(\n sourceFiatRate.usdRate,\n );\n\n return { sourceFiatRate, usdToFiatRate };\n}\n\n/**\n * Calculates source network cost from a Relay quote.\n *\n * For post-quote flows (e.g. predictWithdraw), the cost also includes the\n * original transaction's gas (the user's Polygon USDC.e transfer) in addition\n * to the Relay deposit transaction gas, by appending the original\n * transaction's params so that gas estimation and gas-fee-token logic handle\n * both transactions together.\n *\n * Network fees are zeroed whenever the user does not pay origin gas, either\n * because a relayer covers it or because MetaMask sponsors it.\n *\n * @param quote - Relay quote.\n * @param messenger - Controller messenger.\n * @param request - Quote request.\n * @param transaction - Original transaction metadata.\n * @param accountSupports7702 - Whether the source account supports EIP-7702.\n * @returns Total source network cost in USD and fiat.\n */\nasync function calculateSourceNetworkCost(\n quote: RelayQuote,\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n transaction: TransactionMeta,\n accountSupports7702: boolean | undefined,\n): Promise<\n TransactionPayQuote<RelayQuote>['fees']['sourceNetwork'] & {\n gasLimits: number[];\n isGasFeeToken?: boolean;\n is7702: boolean;\n }\n> {\n const { from, sourceChainId, sourceTokenAddress } = request;\n\n // None of these flows bill origin gas to the user: the execute flow has a\n // relayer redeem a signed delegation, a HyperLiquid withdrawal's \"deposit\"\n // step is an off-chain HL sendAsset signature rather than an on-chain\n // transaction, and a Polymarket deposit-wallet withdraw is submitted by the\n // Polymarket relayer.\n const isExecuteFlow = Boolean(quote.metamask?.isExecute);\n const isHyperliquidWithdrawal = Boolean(request.isHyperliquidSource);\n const isPolymarketDepositWallet = Boolean(request.isPolymarketDepositWallet);\n\n const gasPayment = resolveGasPayment({\n isDelegated:\n isExecuteFlow || isHyperliquidWithdrawal || isPolymarketDepositWallet,\n sourceTokenAddress,\n sponsorship: {\n accountSupports7702,\n request,\n transaction,\n },\n });\n\n if (gasPayment.mode === GasPaymentMode.Delegation) {\n log('Zeroing network fees as the user does not pay origin gas', {\n isExecuteFlow,\n isHyperliquidWithdrawal,\n isPolymarketDepositWallet,\n });\n\n return {\n estimate: ZERO_AMOUNT,\n max: ZERO_AMOUNT,\n gasLimits: [],\n is7702: false,\n };\n }\n\n if (gasPayment.mode === GasPaymentMode.Sponsored) {\n log('Zeroing source network fees for sponsored same-chain Relay route');\n\n // Gas limit is zero as sponsored transactions go through the EIP-7702\n // gas station hook and do not require user-paid gas.\n return {\n estimate: ZERO_AMOUNT,\n max: ZERO_AMOUNT,\n gasLimits: [0],\n is7702: true,\n };\n }\n\n const txSteps = quote.steps.filter(\n (step): step is RelayTransactionStep => step.kind === 'transaction',\n );\n const relayParams = txSteps\n .flatMap((step) => step.items)\n .map((item) => item.data);\n\n const { chainId, data, maxFeePerGas, maxPriorityFeePerGas, to, value } =\n relayParams[0];\n\n // `fromOverride = Safe proxy` is only valid for deposit-style Relay routes\n // where the deposit contract reads the user's source-token balance directly.\n // Same-chain destinations route through DEX swap aggregators that frequently\n // reject contract callers (anti-MEV `msg.sender == tx.origin` checks,\n // ERC777-style callback interfaces, native wrap/unwrap requiring caller\n // native balance). Simulating those from the Safe proxy reverts and breaks\n // gas estimation. For swap-only routes, fall back to the relay params'\n // EOA `from` so simulation succeeds.\n const fromOverride = getPredictWithdrawSafeAddress(\n request,\n transaction,\n hasRelayDepositStep(quote.steps),\n );\n\n // For post-quote flows the original transaction will be prepended to the\n // batch at submission time. Include it in the gas estimation so\n // estimateGasBatch sees the full batch and can detect EIP-7702 support.\n // Without this, a single relay step is estimated alone, gets is7702=false,\n // and the batch falls back to separate type-0x2 transactions that each\n // need native gas — breaking zero-balance fiat-funded accounts.\n const originalTxGasParams = getOriginalTxGasParams(request, transaction);\n const allGasParams = originalTxGasParams\n ? [originalTxGasParams, ...relayParams]\n : relayParams;\n\n const gasResult = await calculateSourceNetworkGasLimit(\n allGasParams,\n messenger,\n fromOverride,\n );\n\n // When the original tx was NOT included in gas estimation (no gas params\n // available), fall back to the legacy prepend-after-the-fact approach.\n const { gasLimits, is7702, totalGasEstimate, totalGasLimit } =\n originalTxGasParams\n ? gasResult\n : combinePrependedGas(gasResult, request, transaction);\n\n log('Gas limit', {\n is7702,\n totalGasEstimate,\n totalGasLimit,\n gasLimits,\n });\n\n const estimate = calculateGasCost({\n chainId,\n gas: totalGasEstimate,\n maxFeePerGas,\n maxPriorityFeePerGas,\n messenger,\n });\n\n const max = calculateGasCost({\n chainId,\n gas: totalGasLimit,\n maxFeePerGas,\n maxPriorityFeePerGas,\n messenger,\n isMax: true,\n });\n\n const result = { estimate, max, gasLimits, is7702 };\n\n // Gas-fee-token lookup must use the Safe proxy for ALL Predict withdraws,\n // not only deposit-style routes. The user's source token (pUSD) lives in\n // the Safe; the EOA is empty until the Safe.execTransaction sub-call runs\n // mid-batch. Querying the EOA for gas-fee-token availability would always\n // return nothing and force users to hold POL.\n // (`useFromOverride` only governs the gas-estimation `from` address, where\n // swap-style routes need EOA because DEX routers reject contract callers.)\n const proxyFeeTokenAccount = getPredictWithdrawFeeTokenAccount(\n request,\n transaction,\n );\n\n const gasStationCost = await resolveGasStationCost({\n accountSupports7702,\n feeTokenAccount: proxyFeeTokenAccount,\n firstStepData: {\n data,\n to,\n value,\n },\n messenger,\n nativeGasCostRaw: max.raw,\n request: {\n from,\n sourceChainId,\n sourceTokenAddress,\n },\n totalGasEstimate,\n totalItemCount: proxyFeeTokenAccount\n ? relayParams.length + 1\n : Math.max(relayParams.length, gasLimits.length),\n });\n\n if (!gasStationCost.amount) {\n return result;\n }\n\n log('Using gas fee token for source network', {\n gasFeeTokenCost: gasStationCost.amount,\n proxyFeeTokenAccount,\n });\n\n return {\n isGasFeeToken: true,\n estimate: gasStationCost.amount,\n max: gasStationCost.amount,\n gasLimits,\n is7702,\n };\n}\n\n/**\n * Calculate the total gas limit for the source network.\n *\n * @param params - Array of relay transaction parameters.\n * @param messenger - Controller messenger.\n * @param fromOverride - Optional address to use as `from` in gas estimation\n * instead of the address in the relay params. Used in predict withdraw flows\n * to estimate with the proxy/Safe address that holds the source token balance.\n * @returns Total gas estimates and per-transaction gas limits.\n */\nasync function calculateSourceNetworkGasLimit(\n params: RelayTransactionStep['items'][0]['data'][],\n messenger: TransactionPayControllerMessenger,\n fromOverride?: Hex,\n): Promise<{\n totalGasEstimate: number;\n totalGasLimit: number;\n gasLimits: number[];\n is7702: boolean;\n}> {\n const transactions = params.map((singleParams) =>\n toRelayQuoteGasTransaction(singleParams, fromOverride),\n );\n\n const relayGasResult = await estimateQuoteGasLimits({\n fallbackGas: getFeatureFlags(messenger).relayFallbackGas,\n fallbackOnSimulationFailure: true,\n messenger,\n transactions,\n });\n\n return {\n gasLimits: relayGasResult.gasLimits.map((gasLimit) => gasLimit.max),\n is7702: relayGasResult.is7702,\n totalGasEstimate: relayGasResult.totalGasEstimate,\n totalGasLimit: relayGasResult.totalGasLimit,\n };\n}\n\nfunction toRelayQuoteGasTransaction(\n singleParams: RelayTransactionStep['items'][0]['data'],\n fromOverride?: Hex,\n): QuoteGasTransaction {\n return {\n chainId: toHex(singleParams.chainId),\n data: singleParams.data,\n from: fromOverride ?? singleParams.from,\n gas: fromOverride ? undefined : singleParams.gas,\n to: singleParams.to,\n value: singleParams.value ?? '0',\n };\n}\n\nfunction getOriginalTxGasParams(\n request: QuoteRequest,\n transaction: TransactionMeta,\n): RelayStepData | undefined {\n if (!request.isPostQuote) {\n return undefined;\n }\n\n const { txParams } = transaction;\n const to = txParams.to as Hex | undefined;\n\n if (!to) {\n return undefined;\n }\n\n const hasAccountOverride =\n request.from.toLowerCase() !== (txParams.from as Hex).toLowerCase();\n\n if (hasAccountOverride) {\n return undefined;\n }\n\n const nestedGas = transaction.nestedTransactions?.find((tx) => tx.gas)?.gas;\n const gas = nestedGas ?? txParams.gas;\n\n return {\n chainId: Number(transaction.chainId),\n data: (txParams.data as Hex) ?? '0x',\n from: txParams.from as Hex,\n gas: gas ? String(gas) : undefined,\n maxFeePerGas: '0',\n maxPriorityFeePerGas: '0',\n to,\n value: txParams.value ?? '0',\n };\n}\n\nfunction combinePrependedGas(\n relayOnlyGas: RelayGasResult,\n request: QuoteRequest,\n transaction: TransactionMeta,\n): RelayGasResult {\n const gas = request.isPostQuote\n ? combinePostQuoteGas(relayOnlyGas, transaction)\n : relayOnlyGas;\n\n return request.paymentOverride ? addPaymentOverrideGas(gas) : gas;\n}\n\n/**\n * Combine the original transaction's gas with relay gas for post-quote flows.\n *\n * Prefers gas from `nestedTransactions` (preserves the caller-provided value)\n * since TransactionController may re-estimate `txParams.gas` during batch\n * creation.\n *\n * @param relayGas - Gas estimates from relay transactions.\n * @param relayGas.totalGasEstimate - Estimated gas total.\n * @param relayGas.totalGasLimit - Maximum gas total.\n * @param relayGas.gasLimits - Per-transaction gas limits.\n * @param relayGas.is7702 - Whether the relay gas came from a combined 7702 batch estimate.\n * @param transaction - Original transaction metadata.\n * @returns Combined gas estimates including the original transaction.\n */\nfunction combinePostQuoteGas(\n relayGas: RelayGasResult,\n transaction: TransactionMeta,\n): RelayGasResult {\n const nestedGas = transaction.nestedTransactions?.find((tx) => tx.gas)?.gas;\n const rawGas = nestedGas ?? transaction.txParams.gas;\n const originalTxGas = rawGas ? new BigNumber(rawGas).toNumber() : undefined;\n\n if (originalTxGas === undefined) {\n return relayGas;\n }\n\n let { gasLimits } = relayGas;\n\n if (relayGas.is7702) {\n // Combined 7702 gas limit — add the original tx gas so the batch\n // keeps using a single 7702 limit.\n gasLimits = [gasLimits[0] + originalTxGas];\n } else {\n // Multiple individual gas limits — prepend the original tx gas\n // so the list order matches relay-submit's transaction order.\n gasLimits = [originalTxGas, ...gasLimits];\n }\n\n const totalGasEstimate = relayGas.totalGasEstimate + originalTxGas;\n const totalGasLimit = relayGas.totalGasLimit + originalTxGas;\n\n log('Combined original tx gas with relay gas', {\n originalTxGas,\n is7702: relayGas.is7702,\n gasLimits,\n totalGasLimit,\n });\n\n return {\n totalGasEstimate,\n totalGasLimit,\n gasLimits,\n is7702: relayGas.is7702,\n };\n}\n\nfunction addPaymentOverrideGas(relayGas: RelayGasResult): RelayGasResult {\n const gasLimits = relayGas.is7702\n ? [relayGas.gasLimits[0] + PAYMENT_OVERRIDE_GAS]\n : [PAYMENT_OVERRIDE_GAS, ...relayGas.gasLimits];\n\n return {\n totalGasEstimate: relayGas.totalGasEstimate + PAYMENT_OVERRIDE_GAS,\n totalGasLimit: relayGas.totalGasLimit + PAYMENT_OVERRIDE_GAS,\n gasLimits,\n is7702: relayGas.is7702,\n };\n}\n\n/**\n * Calculate the provider fee for a Relay quote.\n *\n * @param quote - Relay quote.\n * @returns - Provider fee in USD.\n */\nfunction calculateProviderFee(quote: RelayQuote): BigNumber {\n return new BigNumber(quote.details.totalImpact.usd).abs();\n}\n\n/**\n * Build token transfer data.\n *\n * @param recipient - Recipient address.\n * @param amountRaw - Amount in raw format.\n * @returns Token transfer data.\n */\nfunction buildTokenTransferData(recipient: Hex, amountRaw: string): Hex {\n return new Interface([\n 'function transfer(address to, uint256 amount)',\n ]).encodeFunctionData('transfer', [recipient, amountRaw]) as Hex;\n}\n\n/**\n * Get transfer recipient from token transfer data.\n *\n * @param data - Token transfer data.\n * @returns Transfer recipient.\n */\nfunction getTransferRecipient(data: Hex): Hex {\n return new Interface(['function transfer(address to, uint256 amount)'])\n .decodeFunctionData('transfer', data)\n .to.toLowerCase();\n}\nfunction getSubsidizedFeeAmountUsd(\n messenger: TransactionPayControllerMessenger,\n quote: RelayQuote,\n): BigNumber {\n const subsidizedFee = quote.fees?.subsidized;\n const amountUsd = new BigNumber(subsidizedFee?.amountUsd ?? '0');\n const amountFormatted = new BigNumber(subsidizedFee?.amountFormatted ?? '0');\n\n if (!subsidizedFee || amountUsd.isZero()) {\n return new BigNumber(0);\n }\n\n const isSubsidizedStablecoin = isStablecoin(\n messenger,\n toHex(subsidizedFee.currency.chainId),\n subsidizedFee.currency.address,\n );\n\n return isSubsidizedStablecoin ? amountFormatted : amountUsd;\n}\n\nfunction isStablecoin(\n messenger: TransactionPayControllerMessenger,\n chainId: string,\n tokenAddress: string,\n): boolean {\n return Boolean(\n getStablecoins(messenger)[chainId as Hex]?.includes(\n tokenAddress.toLowerCase() as Hex,\n ),\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"relay-quotes.js","sourceRoot":"","sources":["../../../src/strategy/relay/relay-quotes.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable require-atomic-updates */\n\nimport { Interface } from '@ethersproject/abi';\nimport { toHex } from '@metamask/controller-utils';\nimport type {\n AuthorizationList,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n ARBITRUM_USDC_ADDRESS,\n CHAIN_ID_ARBITRUM,\n CHAIN_ID_HYPERCORE,\n CHAIN_ID_POLYGON,\n HYPERCORE_USDC_ADDRESS,\n HYPERCORE_USDC_DECIMALS,\n NATIVE_TOKEN_ADDRESS,\n PERPS_DEPOSIT_TYPES,\n USDC_DECIMALS,\n PaymentOverride,\n} from '../../constants.js';\nimport { TransactionPayStrategy } from '../../index.js';\nimport { projectLogger } from '../../logger.js';\nimport type {\n Amount,\n FiatRates,\n PayStrategyGetQuotesRequest,\n QuoteRequest,\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types.js';\nimport { getFiatValueFromUsd } from '../../utils/amounts.js';\nimport {\n getRelayOriginGasOverhead,\n getSlippage,\n getStablecoins,\n isAtomicMaxEnabled,\n isEIP7702Chain,\n isRelayExecuteEnabled,\n} from '../../utils/feature-flags.js';\nimport {\n GasPaymentMode,\n resolveGasPayment,\n resolveGasStationCost,\n} from '../../utils/gas-payment.js';\nimport { calculateGasCost } from '../../utils/gas.js';\nimport {\n getPolymarketDepositWalletOverrides,\n getPredictWithdrawFeeTokenAccount,\n getPredictWithdrawSafeAddress,\n} from '../../utils/polymarket/withdraw.js';\nimport { reservePostQuoteGas } from '../../utils/post-quote.js';\nimport { estimateSourceGas } from '../../utils/quote-gas.js';\nimport type { QuoteGasTransaction } from '../../utils/quote-gas.js';\nimport { resolveNonAtomicRecipient } from '../../utils/second-leg.js';\nimport {\n getNativeToken,\n getTokenFiatRate,\n normalizeTokenAddress,\n TokenAddressTarget,\n} from '../../utils/token.js';\nimport { getQuotePricing } from '../../utils/trade-type.js';\nimport { TOKEN_TRANSFER_FOUR_BYTE } from './constants.js';\nimport { hasRelayDepositStep } from './deposit-step.js';\nimport { applyHyperliquidActivationFee } from './hyperliquid-activation.js';\nimport { fetchRelayQuote } from './relay-api.js';\nimport {\n getRelayMaxQuote,\n isSubsidizedAtomicMaxQuote,\n throwAtomicPromotionFailed,\n} from './relay-max.js';\nimport { validateRelayQuotes } from './relay-validation.js';\nimport type {\n RelayQuote,\n RelayQuoteMetamask,\n RelayQuoteRequest,\n RelayTransactionStep,\n} from './types.js';\n\nconst log = createModuleLogger(projectLogger, 'relay-strategy');\n\nconst ZERO_AMOUNT = { fiat: '0', human: '0', raw: '0', usd: '0' };\n\ntype RelayQuoteRequestDraft = Omit<RelayQuoteRequest, 'amount' | 'tradeType'> &\n Partial<Pick<RelayQuoteRequest, 'amount'>>;\n\n/**\n * Fetches Relay quotes.\n *\n * @param request - Request object.\n * @returns Array of quotes.\n */\nexport async function getRelayQuotes(\n request: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>[]> {\n const { requests } = request;\n\n log('Fetching quotes', requests);\n\n try {\n const normalizedRequests = await Promise.all(\n requests\n .filter((singleRequest) => {\n const hasTargetMinimum = singleRequest.targetAmountMinimum !== '0';\n const isPostQuote = Boolean(singleRequest.isPostQuote);\n const isExactInputRequest =\n Boolean(singleRequest.isMaxAmount) &&\n new BigNumber(singleRequest.sourceTokenAmount).gt(0);\n\n return hasTargetMinimum || isPostQuote || isExactInputRequest;\n })\n .map((singleRequest) =>\n normalizeRequest(singleRequest, request.transaction),\n )\n .map((normalizedRequest) =>\n applyHyperliquidActivationFee(\n normalizedRequest,\n request.messenger,\n request.transaction,\n request.signal,\n ),\n ),\n );\n\n log('Normalized requests', normalizedRequests);\n\n const quotes = await Promise.all(\n normalizedRequests.map((singleRequest) =>\n getQuoteWithMaxAmountHandling(singleRequest, request),\n ),\n );\n\n const atomicMaxQuotes = quotes.filter(isSubsidizedAtomicMaxQuote);\n const otherQuotes = quotes.filter(\n (quote) => !isSubsidizedAtomicMaxQuote(quote),\n );\n\n if (otherQuotes.length > 0) {\n await validateRelayQuotes({\n messenger: request.messenger,\n quotes: otherQuotes,\n signal: request.signal,\n transaction: request.transaction,\n });\n }\n\n if (atomicMaxQuotes.length > 0) {\n try {\n await validateRelayQuotes({\n messenger: request.messenger,\n quotes: atomicMaxQuotes,\n signal: request.signal,\n transaction: request.transaction,\n });\n } catch (error) {\n throwAtomicPromotionFailed(error);\n }\n }\n\n return quotes;\n } catch (error) {\n log('Error fetching quotes', { error });\n throw error;\n }\n}\n\nasync function getQuoteWithMaxAmountHandling(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const { isMaxAmount } = request;\n\n if (!isMaxAmount) {\n return getQuoteWithPostQuoteGasHandling(request, fullRequest);\n }\n\n return getRelayMaxQuote(request, fullRequest, getSingleQuote);\n}\n\n/**\n * For post-quote flows, fetch an initial quote to compute gas cost in source\n * token, then re-quote with the source amount reduced by the gas cost.\n * This ensures Relay reserves enough for the gas fee token payment.\n *\n * For non-post-quote flows, just returns a single quote.\n *\n * @param request - Quote request.\n * @param fullRequest - Full request context.\n * @returns The final quote (phase 2 for post-quote, or phase 1 for normal).\n */\nasync function getQuoteWithPostQuoteGasHandling(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const phase1Quote = await getSingleQuote(request, fullRequest);\n\n if (!request.isPostQuote) {\n return phase1Quote;\n }\n\n if (phase1Quote.original.metamask?.isExecute) {\n return phase1Quote;\n }\n\n return await reservePostQuoteGas({\n quote: phase1Quote,\n requote: (adjustedRequest) => getSingleQuote(adjustedRequest, fullRequest),\n });\n}\n\n/**\n * Fetches a single Relay quote.\n *\n * @param request - Quote request.\n * @param fullRequest - Full quotes request.\n * @returns Single quote.\n */\nasync function getSingleQuote(\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const {\n accountSupports7702: supports7702,\n messenger,\n signal,\n transaction,\n } = fullRequest;\n\n const {\n from,\n sourceChainId,\n sourceTokenAddress,\n sourceTokenAmount,\n targetAmountMinimum,\n targetChainId,\n targetTokenAddress,\n } = request;\n\n const slippageDecimal = getSlippage(\n messenger,\n sourceChainId,\n sourceTokenAddress,\n );\n\n const slippageTolerance = new BigNumber(slippageDecimal * 100 * 100).toFixed(\n 0,\n );\n\n try {\n const useExecute =\n supports7702 &&\n isRelayExecuteEnabled(messenger) &&\n isEIP7702Chain(messenger, sourceChainId);\n\n const nonAtomicRecipient = await resolveNonAtomicRecipient(\n transaction,\n request,\n messenger,\n );\n\n const effectiveRequest = nonAtomicRecipient\n ? { ...request, recipient: nonAtomicRecipient }\n : request;\n\n const body: RelayQuoteRequestDraft = {\n destinationChainId: Number(targetChainId),\n destinationCurrency: targetTokenAddress,\n originChainId: Number(sourceChainId),\n originCurrency: sourceTokenAddress,\n ...(useExecute\n ? {\n originGasOverhead: getRelayOriginGasOverhead(messenger),\n metamask: { executeVersion: 2 },\n }\n : {}),\n recipient: effectiveRequest.recipient ?? from,\n slippageTolerance,\n user: from,\n };\n\n if (effectiveRequest.isPolymarketDepositWallet) {\n const overrides = await getPolymarketDepositWalletOverrides(\n from,\n messenger,\n );\n const { depositWallet } = overrides;\n\n body.originCurrency = overrides.sourceTokenAddress;\n body.user = depositWallet;\n body.refundTo = depositWallet;\n body.useDepositAddress = true;\n body.strict = true;\n }\n\n const isAtomic = effectiveRequest.atomic !== false;\n\n const processedTransactions = await processTransactions(\n transaction,\n effectiveRequest,\n body,\n messenger,\n );\n\n if (\n !processedTransactions &&\n isAtomic &&\n effectiveRequest.isPostQuote &&\n effectiveRequest.paymentOverride === PaymentOverride.MoneyAccount\n ) {\n await processMoneyAccountPostQuote(\n transaction,\n effectiveRequest,\n body,\n messenger,\n );\n } else if (!processedTransactions && effectiveRequest.refundTo) {\n // For post-quote flows, honour the caller-specified refund address so that\n // failed Relay transactions refund to the correct account (e.g. the Predict\n // Safe proxy) rather than defaulting to the EOA.\n body.refundTo = effectiveRequest.refundTo;\n }\n\n const pricing = getQuotePricing({\n hasCalls: Boolean(body.txs?.length),\n sourceTokenAmount,\n targetAmountMinimum,\n transaction,\n });\n\n const finalBody: RelayQuoteRequest = {\n ...body,\n // A step that bundled its own calls has already pinned the amount those\n // calls consume, so it wins over the derived amount.\n amount: body.amount ?? pricing.amount,\n tradeType: pricing.tradeType,\n };\n\n log('Request body', finalBody);\n\n const quote = await fetchRelayQuote(messenger, finalBody, signal);\n\n log('Fetched relay quote', quote);\n\n return await normalizeQuote(quote, effectiveRequest, fullRequest);\n } catch (error) {\n log('Error fetching relay quote', error);\n throw error;\n }\n}\n\nfunction normalizeAuthorizationList(\n authorizationList: AuthorizationList | undefined,\n): RelayQuoteRequest['authorizationList'] {\n return authorizationList?.map((a) => ({\n ...a,\n chainId: Number(a.chainId),\n nonce: Number(a.nonce),\n r: a.r as Hex,\n s: a.s as Hex,\n yParity: Number(a.yParity),\n }));\n}\n\n/**\n * Add tranasction data to request body if needed.\n *\n * @param transaction - Transaction metadata.\n * @param request - Quote request.\n * @param requestBody - Request body to populate.\n * @param messenger - Controller messenger.\n * @returns `true` when the transaction was embedded in the quote; `false` when\n * skipped so the caller can route to an alternate handler.\n */\nasync function processTransactions(\n transaction: TransactionMeta,\n request: QuoteRequest,\n requestBody: RelayQuoteRequestDraft,\n messenger: TransactionPayControllerMessenger,\n): Promise<boolean> {\n // Skip when skipProcessTransactions (defaulting to isPostQuote) is set — the\n // original transaction is submitted separately, not embedded in the quote.\n // Skip Polymarket deposit wallet flows — the source is already a bridged\n // token transfer, not a contract call to embed. Skip non-atomic flows — the\n // second leg is submitted after Relay settlement.\n if (\n (request.skipProcessTransactions ?? request.isPostQuote) === true ||\n request.isPolymarketDepositWallet === true ||\n request.atomic === false\n ) {\n return false;\n }\n\n const { nestedTransactions, txParams } = transaction;\n const { isMaxAmount, targetChainId } = request;\n const data = txParams?.data as Hex | undefined;\n\n const singleData =\n nestedTransactions?.length === 1 ? nestedTransactions[0].data : data;\n\n const isHypercore = targetChainId === CHAIN_ID_HYPERCORE;\n\n const isTokenTransfer =\n !isHypercore && Boolean(singleData?.startsWith(TOKEN_TRANSFER_FOUR_BYTE));\n\n if (isTokenTransfer) {\n requestBody.recipient = getTransferRecipient(singleData as Hex);\n\n log('Updating recipient as token transfer', requestBody.recipient);\n }\n\n const hasNoData = singleData === undefined || singleData === '0x';\n const skipDelegation = hasNoData || isTokenTransfer || isHypercore;\n\n if (skipDelegation) {\n log('Skipping delegation as token transfer or Hypercore deposit');\n return true;\n }\n\n // Eligible atomic max requests carry a destination amount, so the calls\n // below use EXACT_OUTPUT rather than the usual max EXACT_INPUT quote.\n if (\n isMaxAmount &&\n (request.isPostQuote === true ||\n !isAtomicMaxEnabled(messenger, transaction))\n ) {\n throw new Error('Max amount quotes do not support included transactions');\n }\n\n const delegation = await messenger.call(\n 'TransactionPayController:getDelegationTransaction',\n { transaction },\n );\n\n requestBody.authorizationList = normalizeAuthorizationList(\n delegation.authorizationList,\n );\n\n const tokenTransferData = nestedTransactions?.find((nestedTx) =>\n nestedTx.data?.startsWith(TOKEN_TRANSFER_FOUR_BYTE),\n )?.data;\n\n // If the transactions include a token transfer, change the recipient\n // so any extra dust is also sent to the same address, rather than back to the user.\n if (tokenTransferData) {\n requestBody.recipient = getTransferRecipient(tokenTransferData);\n requestBody.refundTo = request.from;\n }\n\n requestBody.txs = [\n {\n to: request.targetTokenAddress,\n data: buildTokenTransferData(\n transaction.txParams.from as Hex,\n request.targetAmountMinimum,\n ),\n value: '0x0',\n },\n {\n to: delegation.to,\n data: delegation.data,\n value: delegation.value,\n },\n ];\n\n return true;\n}\n\nasync function processMoneyAccountPostQuote(\n transaction: TransactionMeta,\n request: QuoteRequest,\n requestBody: RelayQuoteRequestDraft,\n messenger: TransactionPayControllerMessenger,\n): Promise<void> {\n const { transactionData: transactionDataList } = messenger.call(\n 'TransactionPayController:getState',\n );\n\n const transactionData = transactionDataList[transaction.id];\n const amountHuman = transactionData?.tokens?.[0]?.amountHuman ?? '0';\n\n const {\n calls: overrideCalls,\n recipient,\n authorizationList,\n } = await messenger.call('TransactionPayController:getPaymentOverrideData', {\n amount: amountHuman,\n transaction,\n transactionData,\n });\n\n if (!overrideCalls.length) {\n log('No payment override calls for money account post-quote');\n return;\n }\n\n const fundingRecipient = recipient ?? request.from;\n const rawAmount = transactionData?.tokens?.[0]?.amountRaw ?? '0';\n\n requestBody.authorizationList = normalizeAuthorizationList(authorizationList);\n requestBody.amount = rawAmount;\n requestBody.txs = [\n {\n to: request.targetTokenAddress,\n data: buildTokenTransferData(fundingRecipient, rawAmount),\n value: '0x0',\n },\n ...overrideCalls.map((call) => ({\n to: call.to as Hex,\n data: call.data as Hex,\n value: (call.value as Hex) ?? '0x0',\n })),\n ];\n\n log('Added money account deposit calls to quote body', {\n callCount: overrideCalls.length,\n });\n}\n\n/**\n * Normalizes requests for Relay.\n *\n * @param request - Quote request to normalize.\n * @param transaction - Parent transaction metadata, used to gate\n * Hyperliquid-specific rewrites on transaction type.\n * @returns Normalized request.\n */\nfunction normalizeRequest(\n request: QuoteRequest,\n transaction: TransactionMeta,\n): QuoteRequest {\n const newRequest = {\n ...request,\n };\n\n const isPerpsDeposit =\n transaction.type !== undefined &&\n PERPS_DEPOSIT_TYPES.includes(transaction.type);\n\n const isHyperliquidDeposit =\n isPerpsDeposit &&\n !request.isPostQuote &&\n request.targetChainId === CHAIN_ID_ARBITRUM &&\n request.targetTokenAddress.toLowerCase() ===\n ARBITRUM_USDC_ADDRESS.toLowerCase();\n\n newRequest.sourceTokenAddress = normalizeTokenAddress(\n newRequest.sourceTokenAddress,\n newRequest.sourceChainId,\n TokenAddressTarget.Relay,\n );\n newRequest.targetTokenAddress = normalizeTokenAddress(\n newRequest.targetTokenAddress,\n newRequest.targetChainId,\n TokenAddressTarget.Relay,\n );\n\n if (isHyperliquidDeposit) {\n newRequest.targetChainId = CHAIN_ID_HYPERCORE;\n newRequest.targetTokenAddress = HYPERCORE_USDC_ADDRESS;\n newRequest.targetAmountMinimum = new BigNumber(request.targetAmountMinimum)\n .shiftedBy(HYPERCORE_USDC_DECIMALS - USDC_DECIMALS)\n .toString(10);\n\n log('Converting Arbitrum Hyperliquid deposit to direct deposit', {\n originalRequest: request,\n normalizedRequest: newRequest,\n });\n }\n\n // HyperLiquid withdrawal: source is HyperCore Perps USDC, not Arbitrum.\n if (request.isHyperliquidSource) {\n newRequest.sourceChainId = CHAIN_ID_HYPERCORE;\n newRequest.sourceTokenAddress = HYPERCORE_USDC_ADDRESS;\n\n if (newRequest.sourceTokenAmount) {\n newRequest.sourceTokenAmount = new BigNumber(newRequest.sourceTokenAmount)\n .shiftedBy(HYPERCORE_USDC_DECIMALS - USDC_DECIMALS)\n .toString(10);\n }\n }\n\n return newRequest;\n}\n\n/**\n * Normalizes a Relay quote into a TransactionPayQuote.\n *\n * @param quote - Relay quote.\n * @param request - Original quote request.\n * @param fullRequest - Full quotes request.\n * @returns Normalized quote.\n */\nasync function normalizeQuote(\n quote: RelayQuote,\n request: QuoteRequest,\n fullRequest: PayStrategyGetQuotesRequest,\n): Promise<TransactionPayQuote<RelayQuote>> {\n const { messenger } = fullRequest;\n const { details } = quote;\n const { currencyIn, currencyOut } = details;\n\n const { usdToFiatRate } = getFiatRates(messenger, request);\n\n const dust = getFiatValueFromUsd(\n calculateDustUsd(quote, request),\n usdToFiatRate,\n );\n\n const subsidizedFeeUsd = getSubsidizedFeeAmountUsd(messenger, quote);\n\n const appFeeUsd = new BigNumber(quote.fees?.app?.amountUsd ?? '0');\n const metaMaskFee = getFiatValueFromUsd(appFeeUsd, usdToFiatRate);\n\n // Subtract app fee from provider fee since totalImpact.usd already includes\n // it. The relay provider fee is forced to zero when the quote is subsidized,\n // but any reserved HyperLiquid activation fee is withheld from the source\n // send regardless, so it must always be surfaced in the provider fee.\n const activationFeeUsd = new BigNumber(\n request.hyperliquidActivationFeeUsd ?? '0',\n );\n const providerFeeUsd = subsidizedFeeUsd.gt(0)\n ? activationFeeUsd\n : calculateProviderFee(quote).minus(appFeeUsd).plus(activationFeeUsd);\n const provider = getFiatValueFromUsd(providerFeeUsd, usdToFiatRate);\n\n const {\n gasLimits,\n is7702,\n isGasFeeToken: isSourceGasFeeToken,\n ...sourceNetwork\n } = await calculateSourceNetworkCost(\n quote,\n messenger,\n request,\n fullRequest.transaction,\n fullRequest.accountSupports7702,\n );\n\n const targetNetwork = {\n usd: '0',\n fiat: '0',\n };\n\n const sourceAmount: Amount = {\n human: currencyIn.amountFormatted,\n raw: currencyIn.amount,\n ...getFiatValueFromUsd(new BigNumber(currencyIn.amountUsd), usdToFiatRate),\n };\n\n const isTargetStablecoin = isStablecoin(\n messenger,\n request.targetChainId,\n request.targetTokenAddress,\n );\n\n const targetAmountUsd = isTargetStablecoin\n ? new BigNumber(currencyOut.amountFormatted)\n : new BigNumber(currencyOut.amountUsd);\n\n const targetAmount = getFiatValueFromUsd(targetAmountUsd, usdToFiatRate);\n\n const metamask: RelayQuoteMetamask = {\n ...quote.metamask,\n gasLimits: is7702 ? [gasLimits[0]] : gasLimits,\n is7702,\n };\n\n return {\n dust,\n estimatedDuration: details.timeEstimate,\n fees: {\n isSourceGasFeeToken,\n metaMask: metaMaskFee,\n provider,\n sourceNetwork,\n targetNetwork,\n },\n isInputBased: quote.request.tradeType === 'EXACT_INPUT',\n original: {\n ...quote,\n metamask,\n },\n request,\n sourceAmount,\n targetAmount,\n strategy: TransactionPayStrategy.Relay,\n };\n}\n\n/**\n * Calculate dust USD value.\n *\n * @param quote - Relay quote.\n * @param request - Quote request.\n * @returns Dust value in USD and fiat.\n */\nfunction calculateDustUsd(quote: RelayQuote, request: QuoteRequest): BigNumber {\n const { currencyOut } = quote.details;\n const { amountUsd, amountFormatted, minimumAmount } = currencyOut;\n const { decimals: targetDecimals } = currencyOut.currency;\n\n const targetUsdRate = new BigNumber(amountUsd).dividedBy(amountFormatted);\n\n const dustRaw = BigNumber.maximum(\n new BigNumber(minimumAmount).minus(request.targetAmountMinimum),\n 0,\n );\n\n return dustRaw.shiftedBy(-targetDecimals).multipliedBy(targetUsdRate);\n}\n\n/**\n * Calculates USD to fiat rate.\n *\n * @param messenger - Controller messenger.\n * @param request - Quote request.\n * @returns USD to fiat rate.\n */\nfunction getFiatRates(\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n): {\n sourceFiatRate: FiatRates;\n usdToFiatRate: BigNumber;\n} {\n // For HyperLiquid source, the normalized chain/token (HyperCore + Perps USDC)\n // won't have a fiat rate entry. Use Arbitrum USDC instead since Perps USDC\n // is pegged 1:1.\n const sourceChainId = request.isHyperliquidSource\n ? CHAIN_ID_ARBITRUM\n : request.sourceChainId;\n const sourceTokenAddress = request.isHyperliquidSource\n ? ARBITRUM_USDC_ADDRESS\n : request.sourceTokenAddress;\n\n const finalSourceTokenAddress =\n sourceChainId === CHAIN_ID_POLYGON &&\n sourceTokenAddress === NATIVE_TOKEN_ADDRESS\n ? getNativeToken(sourceChainId)\n : sourceTokenAddress;\n\n const sourceFiatRate = getTokenFiatRate(\n messenger,\n finalSourceTokenAddress,\n sourceChainId,\n );\n\n if (!sourceFiatRate) {\n throw new Error('Source token fiat rate not found');\n }\n\n const usdToFiatRate = new BigNumber(sourceFiatRate.fiatRate).dividedBy(\n sourceFiatRate.usdRate,\n );\n\n return { sourceFiatRate, usdToFiatRate };\n}\n\n/**\n * Calculates source network cost from a Relay quote.\n *\n * For post-quote flows (e.g. predictWithdraw), the cost also includes the\n * original transaction's gas (the user's Polygon USDC.e transfer) in addition\n * to the Relay deposit transaction gas, by appending the original\n * transaction's params so that gas estimation and gas-fee-token logic handle\n * both transactions together.\n *\n * Network fees are zeroed whenever the user does not pay origin gas, either\n * because a relayer covers it or because MetaMask sponsors it.\n *\n * @param quote - Relay quote.\n * @param messenger - Controller messenger.\n * @param request - Quote request.\n * @param transaction - Original transaction metadata.\n * @param accountSupports7702 - Whether the source account supports EIP-7702.\n * @returns Total source network cost in USD and fiat.\n */\nasync function calculateSourceNetworkCost(\n quote: RelayQuote,\n messenger: TransactionPayControllerMessenger,\n request: QuoteRequest,\n transaction: TransactionMeta,\n accountSupports7702: boolean | undefined,\n): Promise<\n TransactionPayQuote<RelayQuote>['fees']['sourceNetwork'] & {\n gasLimits: number[];\n isGasFeeToken?: boolean;\n is7702: boolean;\n }\n> {\n const { from, sourceChainId, sourceTokenAddress } = request;\n\n // None of these flows bill origin gas to the user: the execute flow has a\n // relayer redeem a signed delegation, a HyperLiquid withdrawal's \"deposit\"\n // step is an off-chain HL sendAsset signature rather than an on-chain\n // transaction, and a Polymarket deposit-wallet withdraw is submitted by the\n // Polymarket relayer.\n const isExecuteFlow = Boolean(quote.metamask?.isExecute);\n const isHyperliquidWithdrawal = Boolean(request.isHyperliquidSource);\n const isPolymarketDepositWallet = Boolean(request.isPolymarketDepositWallet);\n\n const gasPayment = resolveGasPayment({\n isDelegated:\n isExecuteFlow || isHyperliquidWithdrawal || isPolymarketDepositWallet,\n sourceTokenAddress,\n sponsorship: {\n accountSupports7702,\n request,\n transaction,\n },\n });\n\n if (gasPayment.mode === GasPaymentMode.Delegation) {\n log('Zeroing network fees as the user does not pay origin gas', {\n isExecuteFlow,\n isHyperliquidWithdrawal,\n isPolymarketDepositWallet,\n });\n\n return {\n estimate: ZERO_AMOUNT,\n max: ZERO_AMOUNT,\n gasLimits: [],\n is7702: false,\n };\n }\n\n if (gasPayment.mode === GasPaymentMode.Sponsored) {\n log('Zeroing source network fees for sponsored same-chain Relay route');\n\n // Gas limit is zero as sponsored transactions go through the EIP-7702\n // gas station hook and do not require user-paid gas.\n return {\n estimate: ZERO_AMOUNT,\n max: ZERO_AMOUNT,\n gasLimits: [0],\n is7702: true,\n };\n }\n\n const txSteps = quote.steps.filter(\n (step): step is RelayTransactionStep => step.kind === 'transaction',\n );\n const relayParams = txSteps\n .flatMap((step) => step.items)\n .map((item) => item.data);\n\n const { chainId, data, maxFeePerGas, maxPriorityFeePerGas, to, value } =\n relayParams[0];\n\n // `fromOverride = Safe proxy` is only valid for deposit-style Relay routes\n // where the deposit contract reads the user's source-token balance directly.\n // Same-chain destinations route through DEX swap aggregators that frequently\n // reject contract callers (anti-MEV `msg.sender == tx.origin` checks,\n // ERC777-style callback interfaces, native wrap/unwrap requiring caller\n // native balance). Simulating those from the Safe proxy reverts and breaks\n // gas estimation. For swap-only routes, fall back to the relay params'\n // EOA `from` so simulation succeeds.\n const fromOverride = getPredictWithdrawSafeAddress(\n request,\n transaction,\n hasRelayDepositStep(quote.steps),\n );\n\n const { gasLimits, is7702, totalGasEstimate, totalGasLimit } =\n await estimateSourceGas({\n fromOverride,\n messenger,\n request,\n transaction,\n transactions: relayParams.map(toQuoteGasTransaction),\n });\n\n log('Gas limit', {\n is7702,\n totalGasEstimate,\n totalGasLimit,\n gasLimits,\n });\n\n const estimate = calculateGasCost({\n chainId,\n gas: totalGasEstimate,\n maxFeePerGas,\n maxPriorityFeePerGas,\n messenger,\n });\n\n const max = calculateGasCost({\n chainId,\n gas: totalGasLimit,\n maxFeePerGas,\n maxPriorityFeePerGas,\n messenger,\n isMax: true,\n });\n\n const result = { estimate, max, gasLimits, is7702 };\n\n // Gas-fee-token lookup must use the Safe proxy for ALL Predict withdraws,\n // not only deposit-style routes. The user's source token (pUSD) lives in\n // the Safe; the EOA is empty until the Safe.execTransaction sub-call runs\n // mid-batch. Querying the EOA for gas-fee-token availability would always\n // return nothing and force users to hold POL.\n // (`useFromOverride` only governs the gas-estimation `from` address, where\n // swap-style routes need EOA because DEX routers reject contract callers.)\n const proxyFeeTokenAccount = getPredictWithdrawFeeTokenAccount(\n request,\n transaction,\n );\n\n const gasStationCost = await resolveGasStationCost({\n accountSupports7702,\n feeTokenAccount: proxyFeeTokenAccount,\n firstStepData: {\n data,\n to,\n value,\n },\n messenger,\n nativeGasCostRaw: max.raw,\n request: {\n from,\n sourceChainId,\n sourceTokenAddress,\n },\n totalGasEstimate,\n totalItemCount: proxyFeeTokenAccount\n ? relayParams.length + 1\n : Math.max(relayParams.length, gasLimits.length),\n });\n\n if (!gasStationCost.amount) {\n return result;\n }\n\n log('Using gas fee token for source network', {\n gasFeeTokenCost: gasStationCost.amount,\n proxyFeeTokenAccount,\n });\n\n return {\n isGasFeeToken: true,\n estimate: gasStationCost.amount,\n max: gasStationCost.amount,\n gasLimits,\n is7702,\n };\n}\n\nfunction toQuoteGasTransaction(\n singleParams: RelayTransactionStep['items'][0]['data'],\n): QuoteGasTransaction {\n return {\n chainId: toHex(singleParams.chainId),\n data: singleParams.data,\n from: singleParams.from,\n gas: singleParams.gas,\n to: singleParams.to,\n value: singleParams.value ?? '0',\n };\n}\n\n/**\n * Calculate the provider fee for a Relay quote.\n *\n * @param quote - Relay quote.\n * @returns - Provider fee in USD.\n */\nfunction calculateProviderFee(quote: RelayQuote): BigNumber {\n return new BigNumber(quote.details.totalImpact.usd).abs();\n}\n\n/**\n * Build token transfer data.\n *\n * @param recipient - Recipient address.\n * @param amountRaw - Amount in raw format.\n * @returns Token transfer data.\n */\nfunction buildTokenTransferData(recipient: Hex, amountRaw: string): Hex {\n return new Interface([\n 'function transfer(address to, uint256 amount)',\n ]).encodeFunctionData('transfer', [recipient, amountRaw]) as Hex;\n}\n\n/**\n * Get transfer recipient from token transfer data.\n *\n * @param data - Token transfer data.\n * @returns Transfer recipient.\n */\nfunction getTransferRecipient(data: Hex): Hex {\n return new Interface(['function transfer(address to, uint256 amount)'])\n .decodeFunctionData('transfer', data)\n .to.toLowerCase();\n}\nfunction getSubsidizedFeeAmountUsd(\n messenger: TransactionPayControllerMessenger,\n quote: RelayQuote,\n): BigNumber {\n const subsidizedFee = quote.fees?.subsidized;\n const amountUsd = new BigNumber(subsidizedFee?.amountUsd ?? '0');\n const amountFormatted = new BigNumber(subsidizedFee?.amountFormatted ?? '0');\n\n if (!subsidizedFee || amountUsd.isZero()) {\n return new BigNumber(0);\n }\n\n const isSubsidizedStablecoin = isStablecoin(\n messenger,\n toHex(subsidizedFee.currency.chainId),\n subsidizedFee.currency.address,\n );\n\n return isSubsidizedStablecoin ? amountFormatted : amountUsd;\n}\n\nfunction isStablecoin(\n messenger: TransactionPayControllerMessenger,\n chainId: string,\n tokenAddress: string,\n): boolean {\n return Boolean(\n getStablecoins(messenger)[chainId as Hex]?.includes(\n tokenAddress.toLowerCase() as Hex,\n ),\n );\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { QuoteRequest, TransactionPayQuote } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Re-quote a post-quote flow with the gas cost reserved from the source amount.
|
|
4
|
+
*
|
|
5
|
+
* Gas must come out of the source amount when the balance is fully committed
|
|
6
|
+
* to the quote, either because gas is paid with the source token as a gas fee
|
|
7
|
+
* token or because the source token is itself the native gas token.
|
|
8
|
+
*
|
|
9
|
+
* @param options - Options bag.
|
|
10
|
+
* @param options.quote - Quote for the full source amount.
|
|
11
|
+
* @param options.requote - Fetch a quote for an adjusted request.
|
|
12
|
+
* @returns The re-quoted quote, or the original quote when no reservation is
|
|
13
|
+
* needed or the re-quote is unusable.
|
|
14
|
+
*/
|
|
15
|
+
export declare function reservePostQuoteGas<Original>({ quote, requote, }: {
|
|
16
|
+
quote: TransactionPayQuote<Original>;
|
|
17
|
+
requote: (request: QuoteRequest) => Promise<TransactionPayQuote<Original>>;
|
|
18
|
+
}): Promise<TransactionPayQuote<Original>>;
|
|
19
|
+
//# sourceMappingURL=post-quote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-quote.d.ts","sourceRoot":"","sources":["../../src/utils/post-quote.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AASrE;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,EAClD,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACrC,OAAO,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC;CAC5E,GAAG,OAAO,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CA6DzC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { createModuleLogger } from '@metamask/utils';
|
|
2
|
+
import { BigNumber } from 'bignumber.js';
|
|
3
|
+
import { NATIVE_TOKEN_ADDRESS } from '../constants.js';
|
|
4
|
+
import { projectLogger } from '../logger.js';
|
|
5
|
+
import { getNativeToken } from './token.js';
|
|
6
|
+
const log = createModuleLogger(projectLogger, 'post-quote');
|
|
7
|
+
// Buffer applied to the gas cost when reserving native tokens for gas in
|
|
8
|
+
// post-quote flows, accounting for gas limit re-estimation variance.
|
|
9
|
+
const POST_QUOTE_GAS_BUFFER = 1.1;
|
|
10
|
+
/**
|
|
11
|
+
* Re-quote a post-quote flow with the gas cost reserved from the source amount.
|
|
12
|
+
*
|
|
13
|
+
* Gas must come out of the source amount when the balance is fully committed
|
|
14
|
+
* to the quote, either because gas is paid with the source token as a gas fee
|
|
15
|
+
* token or because the source token is itself the native gas token.
|
|
16
|
+
*
|
|
17
|
+
* @param options - Options bag.
|
|
18
|
+
* @param options.quote - Quote for the full source amount.
|
|
19
|
+
* @param options.requote - Fetch a quote for an adjusted request.
|
|
20
|
+
* @returns The re-quoted quote, or the original quote when no reservation is
|
|
21
|
+
* needed or the re-quote is unusable.
|
|
22
|
+
*/
|
|
23
|
+
export async function reservePostQuoteGas({ quote, requote, }) {
|
|
24
|
+
const { request } = quote;
|
|
25
|
+
if (!request.isPostQuote) {
|
|
26
|
+
return quote;
|
|
27
|
+
}
|
|
28
|
+
if (!quote.fees.isSourceGasFeeToken && !isNativeSource(request)) {
|
|
29
|
+
return quote;
|
|
30
|
+
}
|
|
31
|
+
const gasCostRaw = new BigNumber(quote.fees.sourceNetwork.max.raw)
|
|
32
|
+
.multipliedBy(POST_QUOTE_GAS_BUFFER)
|
|
33
|
+
.integerValue(BigNumber.ROUND_UP);
|
|
34
|
+
const existingHeadroom = new BigNumber(request.sourceBalanceRaw).minus(request.sourceTokenAmount);
|
|
35
|
+
if (existingHeadroom.isGreaterThanOrEqualTo(gasCostRaw)) {
|
|
36
|
+
log('Sufficient existing balance for gas, skipping subtraction', {
|
|
37
|
+
existingHeadroom: existingHeadroom.toString(10),
|
|
38
|
+
gasCostRaw: gasCostRaw.toString(10),
|
|
39
|
+
});
|
|
40
|
+
return quote;
|
|
41
|
+
}
|
|
42
|
+
const adjustedSourceAmount = new BigNumber(request.sourceTokenAmount)
|
|
43
|
+
.minus(gasCostRaw)
|
|
44
|
+
.integerValue(BigNumber.ROUND_DOWN);
|
|
45
|
+
log('Subtracting gas from source for post-quote', {
|
|
46
|
+
adjustedSourceAmount: adjustedSourceAmount.toString(10),
|
|
47
|
+
gasCostRaw,
|
|
48
|
+
originalSourceAmount: request.sourceTokenAmount,
|
|
49
|
+
});
|
|
50
|
+
if (!adjustedSourceAmount.isGreaterThan(0)) {
|
|
51
|
+
log('Insufficient balance after gas subtraction, using original quote');
|
|
52
|
+
return quote;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const adjustedQuote = await requote({
|
|
56
|
+
...request,
|
|
57
|
+
sourceTokenAmount: adjustedSourceAmount.toFixed(0, BigNumber.ROUND_DOWN),
|
|
58
|
+
});
|
|
59
|
+
if (quote.fees.isSourceGasFeeToken &&
|
|
60
|
+
!adjustedQuote.fees.isSourceGasFeeToken) {
|
|
61
|
+
log('Re-quote lost gas fee token eligibility, using original quote');
|
|
62
|
+
return quote;
|
|
63
|
+
}
|
|
64
|
+
return adjustedQuote;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
log('Re-quote failed, using original quote', { error });
|
|
68
|
+
return quote;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function isNativeSource(request) {
|
|
72
|
+
const sourceToken = request.sourceTokenAddress.toLowerCase();
|
|
73
|
+
return (sourceToken === getNativeToken(request.sourceChainId).toLowerCase() ||
|
|
74
|
+
sourceToken === NATIVE_TOKEN_ADDRESS.toLowerCase());
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=post-quote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-quote.js","sourceRoot":"","sources":["../../src/utils/post-quote.ts"],"names":[],"mappings":"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","sourcesContent":["import { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport { NATIVE_TOKEN_ADDRESS } from '../constants.js';\nimport { projectLogger } from '../logger.js';\nimport type { QuoteRequest, TransactionPayQuote } from '../types.js';\nimport { getNativeToken } from './token.js';\n\nconst log = createModuleLogger(projectLogger, 'post-quote');\n\n// Buffer applied to the gas cost when reserving native tokens for gas in\n// post-quote flows, accounting for gas limit re-estimation variance.\nconst POST_QUOTE_GAS_BUFFER = 1.1;\n\n/**\n * Re-quote a post-quote flow with the gas cost reserved from the source amount.\n *\n * Gas must come out of the source amount when the balance is fully committed\n * to the quote, either because gas is paid with the source token as a gas fee\n * token or because the source token is itself the native gas token.\n *\n * @param options - Options bag.\n * @param options.quote - Quote for the full source amount.\n * @param options.requote - Fetch a quote for an adjusted request.\n * @returns The re-quoted quote, or the original quote when no reservation is\n * needed or the re-quote is unusable.\n */\nexport async function reservePostQuoteGas<Original>({\n quote,\n requote,\n}: {\n quote: TransactionPayQuote<Original>;\n requote: (request: QuoteRequest) => Promise<TransactionPayQuote<Original>>;\n}): Promise<TransactionPayQuote<Original>> {\n const { request } = quote;\n\n if (!request.isPostQuote) {\n return quote;\n }\n\n if (!quote.fees.isSourceGasFeeToken && !isNativeSource(request)) {\n return quote;\n }\n\n const gasCostRaw = new BigNumber(quote.fees.sourceNetwork.max.raw)\n .multipliedBy(POST_QUOTE_GAS_BUFFER)\n .integerValue(BigNumber.ROUND_UP);\n\n const existingHeadroom = new BigNumber(request.sourceBalanceRaw).minus(\n request.sourceTokenAmount,\n );\n\n if (existingHeadroom.isGreaterThanOrEqualTo(gasCostRaw)) {\n log('Sufficient existing balance for gas, skipping subtraction', {\n existingHeadroom: existingHeadroom.toString(10),\n gasCostRaw: gasCostRaw.toString(10),\n });\n return quote;\n }\n\n const adjustedSourceAmount = new BigNumber(request.sourceTokenAmount)\n .minus(gasCostRaw)\n .integerValue(BigNumber.ROUND_DOWN);\n\n log('Subtracting gas from source for post-quote', {\n adjustedSourceAmount: adjustedSourceAmount.toString(10),\n gasCostRaw,\n originalSourceAmount: request.sourceTokenAmount,\n });\n\n if (!adjustedSourceAmount.isGreaterThan(0)) {\n log('Insufficient balance after gas subtraction, using original quote');\n return quote;\n }\n\n try {\n const adjustedQuote = await requote({\n ...request,\n sourceTokenAmount: adjustedSourceAmount.toFixed(0, BigNumber.ROUND_DOWN),\n });\n\n if (\n quote.fees.isSourceGasFeeToken &&\n !adjustedQuote.fees.isSourceGasFeeToken\n ) {\n log('Re-quote lost gas fee token eligibility, using original quote');\n return quote;\n }\n\n return adjustedQuote;\n } catch (error) {\n log('Re-quote failed, using original quote', { error });\n return quote;\n }\n}\n\nfunction isNativeSource(request: QuoteRequest): boolean {\n const sourceToken = request.sourceTokenAddress.toLowerCase();\n\n return (\n sourceToken === getNativeToken(request.sourceChainId).toLowerCase() ||\n sourceToken === NATIVE_TOKEN_ADDRESS.toLowerCase()\n );\n}\n"]}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { TransactionMeta } from '@metamask/transaction-controller';
|
|
1
2
|
import type { Hex } from '@metamask/utils';
|
|
2
3
|
import type { TransactionPayControllerMessenger } from '../index.js';
|
|
4
|
+
import type { QuoteRequest } from '../types.js';
|
|
3
5
|
export type QuoteGasTransaction = {
|
|
4
6
|
chainId: Hex;
|
|
5
7
|
data: Hex;
|
|
@@ -12,6 +14,13 @@ export type QuoteGasLimit = {
|
|
|
12
14
|
estimate: number;
|
|
13
15
|
max: number;
|
|
14
16
|
};
|
|
17
|
+
/** Gas required on the source chain, including any prepended transactions. */
|
|
18
|
+
export type SourceGas = {
|
|
19
|
+
gasLimits: number[];
|
|
20
|
+
is7702: boolean;
|
|
21
|
+
totalGasEstimate: number;
|
|
22
|
+
totalGasLimit: number;
|
|
23
|
+
};
|
|
15
24
|
export declare function estimateQuoteGasLimits({ fallbackGas, fallbackOnSimulationFailure, messenger, transactions, }: {
|
|
16
25
|
fallbackGas?: {
|
|
17
26
|
estimate: number;
|
|
@@ -29,4 +38,31 @@ export declare function estimateQuoteGasLimits({ fallbackGas, fallbackOnSimulati
|
|
|
29
38
|
totalGasLimit: number;
|
|
30
39
|
usedBatch: boolean;
|
|
31
40
|
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Estimate the source-chain gas for a quote's transactions, including the
|
|
43
|
+
* transactions prepended at submit time.
|
|
44
|
+
*
|
|
45
|
+
* Post-quote flows prepend the original transaction, so it is estimated with
|
|
46
|
+
* the quote transactions to let batch estimation detect EIP-7702 support.
|
|
47
|
+
* Without it a single quote step is estimated alone, gets `is7702: false`, and
|
|
48
|
+
* the batch falls back to separate transactions that each need native gas.
|
|
49
|
+
* When the original transaction cannot be estimated, fixed allowances for the
|
|
50
|
+
* prepended transactions are added instead.
|
|
51
|
+
*
|
|
52
|
+
* @param options - Options bag.
|
|
53
|
+
* @param options.fromOverride - Address to estimate from instead of each
|
|
54
|
+
* transaction's own `from`, such as the Predict Safe holding the source token.
|
|
55
|
+
* @param options.messenger - Controller messenger.
|
|
56
|
+
* @param options.request - Quote request.
|
|
57
|
+
* @param options.transaction - Original transaction metadata.
|
|
58
|
+
* @param options.transactions - Quote transactions to estimate.
|
|
59
|
+
* @returns Source gas, with per-transaction limits in submission order.
|
|
60
|
+
*/
|
|
61
|
+
export declare function estimateSourceGas({ fromOverride, messenger, request, transaction, transactions, }: {
|
|
62
|
+
fromOverride?: Hex;
|
|
63
|
+
messenger: TransactionPayControllerMessenger;
|
|
64
|
+
request: QuoteRequest;
|
|
65
|
+
transaction: TransactionMeta;
|
|
66
|
+
transactions: QuoteGasTransaction[];
|
|
67
|
+
}): Promise<SourceGas>;
|
|
32
68
|
//# sourceMappingURL=quote-gas.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quote-gas.d.ts","sourceRoot":"","sources":["../../src/utils/quote-gas.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"quote-gas.d.ts","sourceRoot":"","sources":["../../src/utils/quote-gas.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,eAAe,EAChB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAI3C,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,aAAa,CAAC;AAErE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAShD,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,GAAG,CAAC;IACb,IAAI,EAAE,GAAG,CAAC;IACV,IAAI,EAAE,GAAG,CAAC;IACV,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,EAAE,EAAE,GAAG,CAAC;IACR,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,SAAS,GAAG;IACtB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAsB,sBAAsB,CAAC,EAC3C,WAAW,EACX,2BAAmC,EACnC,SAAS,EACT,YAAY,GACb,EAAE;IACD,WAAW,CAAC,EAAE;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,SAAS,EAAE,iCAAiC,CAAC;IAC7C,YAAY,EAAE,mBAAmB,EAAE,CAAC;CACrC,GAAG,OAAO,CAAC;IACV,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,yBAAyB,CAAC,EAAE,IAAI,CAAC;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC,CAwBD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,iBAAiB,CAAC,EACtC,YAAY,EACZ,SAAS,EACT,OAAO,EACP,WAAW,EACX,YAAY,GACb,EAAE;IACD,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,SAAS,EAAE,iCAAiC,CAAC;IAC7C,OAAO,EAAE,YAAY,CAAC;IACtB,WAAW,EAAE,eAAe,CAAC;IAC7B,YAAY,EAAE,mBAAmB,EAAE,CAAC;CACrC,GAAG,OAAO,CAAC,SAAS,CAAC,CA0BrB"}
|
package/dist/utils/quote-gas.js
CHANGED
|
@@ -2,9 +2,11 @@ import { toHex } from '@metamask/controller-utils';
|
|
|
2
2
|
import { createModuleLogger } from '@metamask/utils';
|
|
3
3
|
import { BigNumber } from 'bignumber.js';
|
|
4
4
|
import { projectLogger } from '../logger.js';
|
|
5
|
-
import { getGasBuffer } from './feature-flags.js';
|
|
5
|
+
import { getFeatureFlags, getGasBuffer } from './feature-flags.js';
|
|
6
6
|
import { estimateGasLimit } from './gas.js';
|
|
7
7
|
const log = createModuleLogger(projectLogger, 'quote-gas');
|
|
8
|
+
// Hardcoded gas allowance for the prepended payment override transaction(s).
|
|
9
|
+
const PAYMENT_OVERRIDE_GAS = 75_000;
|
|
8
10
|
export async function estimateQuoteGasLimits({ fallbackGas, fallbackOnSimulationFailure = false, messenger, transactions, }) {
|
|
9
11
|
if (transactions.length === 0) {
|
|
10
12
|
throw new Error('Quote gas estimation requires at least one transaction');
|
|
@@ -27,6 +29,45 @@ export async function estimateQuoteGasLimits({ fallbackGas, fallbackOnSimulation
|
|
|
27
29
|
usedBatch: false,
|
|
28
30
|
};
|
|
29
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Estimate the source-chain gas for a quote's transactions, including the
|
|
34
|
+
* transactions prepended at submit time.
|
|
35
|
+
*
|
|
36
|
+
* Post-quote flows prepend the original transaction, so it is estimated with
|
|
37
|
+
* the quote transactions to let batch estimation detect EIP-7702 support.
|
|
38
|
+
* Without it a single quote step is estimated alone, gets `is7702: false`, and
|
|
39
|
+
* the batch falls back to separate transactions that each need native gas.
|
|
40
|
+
* When the original transaction cannot be estimated, fixed allowances for the
|
|
41
|
+
* prepended transactions are added instead.
|
|
42
|
+
*
|
|
43
|
+
* @param options - Options bag.
|
|
44
|
+
* @param options.fromOverride - Address to estimate from instead of each
|
|
45
|
+
* transaction's own `from`, such as the Predict Safe holding the source token.
|
|
46
|
+
* @param options.messenger - Controller messenger.
|
|
47
|
+
* @param options.request - Quote request.
|
|
48
|
+
* @param options.transaction - Original transaction metadata.
|
|
49
|
+
* @param options.transactions - Quote transactions to estimate.
|
|
50
|
+
* @returns Source gas, with per-transaction limits in submission order.
|
|
51
|
+
*/
|
|
52
|
+
export async function estimateSourceGas({ fromOverride, messenger, request, transaction, transactions, }) {
|
|
53
|
+
const originalTransaction = getOriginalTransactionGas(request, transaction);
|
|
54
|
+
const allTransactions = (originalTransaction ? [originalTransaction, ...transactions] : transactions).map((singleTransaction) => fromOverride
|
|
55
|
+
? { ...singleTransaction, from: fromOverride, gas: undefined }
|
|
56
|
+
: singleTransaction);
|
|
57
|
+
const result = await estimateQuoteGasLimits({
|
|
58
|
+
fallbackGas: getFeatureFlags(messenger).relayFallbackGas,
|
|
59
|
+
fallbackOnSimulationFailure: true,
|
|
60
|
+
messenger,
|
|
61
|
+
transactions: allTransactions,
|
|
62
|
+
});
|
|
63
|
+
const gas = {
|
|
64
|
+
gasLimits: result.gasLimits.map((gasLimit) => gasLimit.max),
|
|
65
|
+
is7702: result.is7702,
|
|
66
|
+
totalGasEstimate: result.totalGasEstimate,
|
|
67
|
+
totalGasLimit: result.totalGasLimit,
|
|
68
|
+
};
|
|
69
|
+
return originalTransaction ? gas : addPrependedGas(gas, request, transaction);
|
|
70
|
+
}
|
|
30
71
|
async function estimateQuoteGasLimitsBatch(transactions, messenger) {
|
|
31
72
|
const [firstTransaction] = transactions;
|
|
32
73
|
const gasBuffer = getGasBuffer(messenger, firstTransaction.chainId);
|
|
@@ -137,4 +178,55 @@ function parseGasLimit(gas) {
|
|
|
137
178
|
}
|
|
138
179
|
return parsedGas.toNumber();
|
|
139
180
|
}
|
|
181
|
+
function getOriginalTransactionGas(request, transaction) {
|
|
182
|
+
const { txParams } = transaction;
|
|
183
|
+
const to = txParams.to;
|
|
184
|
+
if (!request.isPostQuote || !to || hasAccountOverride(request, transaction)) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
const gas = getOriginalGas(transaction);
|
|
188
|
+
return {
|
|
189
|
+
chainId: transaction.chainId,
|
|
190
|
+
data: txParams.data ?? '0x',
|
|
191
|
+
from: txParams.from,
|
|
192
|
+
gas: gas ? String(gas) : undefined,
|
|
193
|
+
to,
|
|
194
|
+
value: txParams.value ?? '0',
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function addPrependedGas(gas, request, transaction) {
|
|
198
|
+
const originalGas = request.isPostQuote
|
|
199
|
+
? getOriginalGas(transaction)
|
|
200
|
+
: undefined;
|
|
201
|
+
const withOriginal = originalGas
|
|
202
|
+
? prependGas(gas, new BigNumber(originalGas).toNumber())
|
|
203
|
+
: gas;
|
|
204
|
+
return request.paymentOverride
|
|
205
|
+
? prependGas(withOriginal, PAYMENT_OVERRIDE_GAS)
|
|
206
|
+
: withOriginal;
|
|
207
|
+
}
|
|
208
|
+
function prependGas(gas, prependedGas) {
|
|
209
|
+
// A combined 7702 limit stays a single limit, otherwise the prepended
|
|
210
|
+
// transaction gets its own limit ahead of the quote transactions.
|
|
211
|
+
const gasLimits = gas.is7702
|
|
212
|
+
? [gas.gasLimits[0] + prependedGas]
|
|
213
|
+
: [prependedGas, ...gas.gasLimits];
|
|
214
|
+
log('Added prepended transaction gas', { gasLimits, prependedGas });
|
|
215
|
+
return {
|
|
216
|
+
gasLimits,
|
|
217
|
+
is7702: gas.is7702,
|
|
218
|
+
totalGasEstimate: gas.totalGasEstimate + prependedGas,
|
|
219
|
+
totalGasLimit: gas.totalGasLimit + prependedGas,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
// Prefer the caller-provided nested gas, since the transaction controller may
|
|
223
|
+
// re-estimate `txParams.gas` during batch creation.
|
|
224
|
+
function getOriginalGas(transaction) {
|
|
225
|
+
return (transaction.nestedTransactions?.find((nested) => nested.gas)?.gas ??
|
|
226
|
+
transaction.txParams.gas);
|
|
227
|
+
}
|
|
228
|
+
function hasAccountOverride(request, transaction) {
|
|
229
|
+
return (request.from.toLowerCase() !==
|
|
230
|
+
transaction.txParams.from.toLowerCase());
|
|
231
|
+
}
|
|
140
232
|
//# sourceMappingURL=quote-gas.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quote-gas.js","sourceRoot":"","sources":["../../src/utils/quote-gas.ts"],"names":[],"mappings":"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","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport type { BatchTransactionParams } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport type { TransactionPayControllerMessenger } from '../index.js';\nimport { projectLogger } from '../logger.js';\nimport { getGasBuffer } from './feature-flags.js';\nimport { estimateGasLimit } from './gas.js';\n\nconst log = createModuleLogger(projectLogger, 'quote-gas');\n\nexport type QuoteGasTransaction = {\n chainId: Hex;\n data: Hex;\n from: Hex;\n gas?: number | string;\n to: Hex;\n value?: number | string | Hex;\n};\n\nexport type QuoteGasLimit = {\n estimate: number;\n max: number;\n};\n\nexport async function estimateQuoteGasLimits({\n fallbackGas,\n fallbackOnSimulationFailure = false,\n messenger,\n transactions,\n}: {\n fallbackGas?: {\n estimate: number;\n max: number;\n };\n fallbackOnSimulationFailure?: boolean;\n messenger: TransactionPayControllerMessenger;\n transactions: QuoteGasTransaction[];\n}): Promise<{\n batchGasLimit?: QuoteGasLimit;\n gasLimits: QuoteGasLimit[];\n is7702: boolean;\n requiresAuthorizationList?: true;\n totalGasEstimate: number;\n totalGasLimit: number;\n usedBatch: boolean;\n}> {\n if (transactions.length === 0) {\n throw new Error('Quote gas estimation requires at least one transaction');\n }\n\n const useBatch = transactions.length > 1;\n\n if (useBatch) {\n return {\n ...(await estimateQuoteGasLimitsBatch(transactions, messenger)),\n usedBatch: true,\n };\n }\n\n return {\n ...(await estimateQuoteGasLimitSingle({\n fallbackGas,\n fallbackOnSimulationFailure,\n messenger,\n transaction: transactions[0],\n })),\n is7702: false,\n usedBatch: false,\n };\n}\n\nasync function estimateQuoteGasLimitsBatch(\n transactions: QuoteGasTransaction[],\n messenger: TransactionPayControllerMessenger,\n): Promise<{\n batchGasLimit?: QuoteGasLimit;\n gasLimits: QuoteGasLimit[];\n is7702: boolean;\n requiresAuthorizationList?: true;\n totalGasEstimate: number;\n totalGasLimit: number;\n}> {\n const [firstTransaction] = transactions;\n const gasBuffer = getGasBuffer(messenger, firstTransaction.chainId);\n\n const paramGasLimits = transactions.map((transaction) =>\n parseGasLimit(transaction.gas),\n );\n\n const { gasLimits, requiresAuthorizationList } = await messenger.call(\n 'TransactionController:estimateGasBatch',\n {\n chainId: firstTransaction.chainId,\n from: firstTransaction.from,\n transactions: transactions.map(toBatchTransactionParams),\n },\n );\n\n if (gasLimits.length !== 1 && gasLimits.length !== transactions.length) {\n throw new Error('Unexpected batch gas limit count');\n }\n\n const bufferedGasLimits = gasLimits.map((gasLimit, index) => {\n const providedGasLimit = paramGasLimits[index];\n const providedGasWasPreserved =\n providedGasLimit !== undefined && providedGasLimit === gasLimit;\n\n // Per-entry batch results currently preserve validated input gas values\n // for transactions that already provided gas. If that contract changes\n // and batch estimation returns a different value, treat it as a fresh\n // estimate and apply the buffer. A single combined 7702 result is always\n // buffered because it is a fresh batch estimate.\n const useBuffer = gasLimits.length === 1 || !providedGasWasPreserved;\n const bufferedGas = Math.ceil(gasLimit * (useBuffer ? gasBuffer : 1));\n\n return {\n estimate: bufferedGas,\n max: bufferedGas,\n };\n });\n\n const totalGasLimit = bufferedGasLimits.reduce(\n (acc, gasLimit) => acc + gasLimit.max,\n 0,\n );\n const is7702 = bufferedGasLimits.length === 1;\n const batchGasLimit = is7702 ? bufferedGasLimits[0] : undefined;\n\n return {\n ...(batchGasLimit ? { batchGasLimit } : {}),\n gasLimits: bufferedGasLimits,\n is7702,\n ...(requiresAuthorizationList ? { requiresAuthorizationList } : {}),\n totalGasEstimate: totalGasLimit,\n totalGasLimit,\n };\n}\n\nasync function estimateQuoteGasLimitSingle({\n fallbackGas,\n fallbackOnSimulationFailure,\n messenger,\n transaction,\n}: {\n fallbackGas?: {\n estimate: number;\n max: number;\n };\n fallbackOnSimulationFailure: boolean;\n messenger: TransactionPayControllerMessenger;\n transaction: QuoteGasTransaction;\n}): Promise<{\n gasLimits: QuoteGasLimit[];\n totalGasEstimate: number;\n totalGasLimit: number;\n}> {\n const providedGasLimit = parseGasLimit(transaction.gas);\n\n if (providedGasLimit !== undefined) {\n log('Using provided gas limit', {\n chainId: transaction.chainId,\n gas: providedGasLimit,\n index: 0,\n to: transaction.to,\n });\n\n return {\n gasLimits: [\n {\n estimate: providedGasLimit,\n max: providedGasLimit,\n },\n ],\n totalGasEstimate: providedGasLimit,\n totalGasLimit: providedGasLimit,\n };\n }\n\n const gasLimitResult = await estimateGasLimit({\n chainId: transaction.chainId,\n data: transaction.data,\n fallbackGas,\n fallbackOnSimulationFailure,\n from: transaction.from,\n messenger,\n to: transaction.to,\n value: toHex(transaction.value ?? '0'),\n });\n\n if (gasLimitResult.usedFallback) {\n log('Gas estimate failed, using fallback', {\n chainId: transaction.chainId,\n error: gasLimitResult.error,\n index: 0,\n to: transaction.to,\n });\n }\n\n const gasLimit = {\n estimate: gasLimitResult.estimate,\n max: gasLimitResult.max,\n };\n\n return {\n gasLimits: [gasLimit],\n totalGasEstimate: gasLimit.estimate,\n totalGasLimit: gasLimit.max,\n };\n}\n\nfunction toBatchTransactionParams(\n transaction: QuoteGasTransaction,\n): BatchTransactionParams {\n return {\n data: transaction.data,\n gas: transaction.gas === undefined ? undefined : toHex(transaction.gas),\n maxFeePerGas: undefined,\n maxPriorityFeePerGas: undefined,\n to: transaction.to,\n value: toHex(transaction.value ?? '0'),\n };\n}\n\nfunction parseGasLimit(gas?: number | string): number | undefined {\n if (gas === undefined) {\n return undefined;\n }\n\n const parsedGas = new BigNumber(gas);\n\n if (\n !parsedGas.isFinite() ||\n parsedGas.isNaN() ||\n !parsedGas.isInteger() ||\n parsedGas.lte(0)\n ) {\n return undefined;\n }\n\n return parsedGas.toNumber();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"quote-gas.js","sourceRoot":"","sources":["../../src/utils/quote-gas.ts"],"names":[],"mappings":"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","sourcesContent":["import { toHex } from '@metamask/controller-utils';\nimport type {\n BatchTransactionParams,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport type { TransactionPayControllerMessenger } from '../index.js';\nimport { projectLogger } from '../logger.js';\nimport type { QuoteRequest } from '../types.js';\nimport { getFeatureFlags, getGasBuffer } from './feature-flags.js';\nimport { estimateGasLimit } from './gas.js';\n\nconst log = createModuleLogger(projectLogger, 'quote-gas');\n\n// Hardcoded gas allowance for the prepended payment override transaction(s).\nconst PAYMENT_OVERRIDE_GAS = 75_000;\n\nexport type QuoteGasTransaction = {\n chainId: Hex;\n data: Hex;\n from: Hex;\n gas?: number | string;\n to: Hex;\n value?: number | string | Hex;\n};\n\nexport type QuoteGasLimit = {\n estimate: number;\n max: number;\n};\n\n/** Gas required on the source chain, including any prepended transactions. */\nexport type SourceGas = {\n gasLimits: number[];\n is7702: boolean;\n totalGasEstimate: number;\n totalGasLimit: number;\n};\n\nexport async function estimateQuoteGasLimits({\n fallbackGas,\n fallbackOnSimulationFailure = false,\n messenger,\n transactions,\n}: {\n fallbackGas?: {\n estimate: number;\n max: number;\n };\n fallbackOnSimulationFailure?: boolean;\n messenger: TransactionPayControllerMessenger;\n transactions: QuoteGasTransaction[];\n}): Promise<{\n batchGasLimit?: QuoteGasLimit;\n gasLimits: QuoteGasLimit[];\n is7702: boolean;\n requiresAuthorizationList?: true;\n totalGasEstimate: number;\n totalGasLimit: number;\n usedBatch: boolean;\n}> {\n if (transactions.length === 0) {\n throw new Error('Quote gas estimation requires at least one transaction');\n }\n\n const useBatch = transactions.length > 1;\n\n if (useBatch) {\n return {\n ...(await estimateQuoteGasLimitsBatch(transactions, messenger)),\n usedBatch: true,\n };\n }\n\n return {\n ...(await estimateQuoteGasLimitSingle({\n fallbackGas,\n fallbackOnSimulationFailure,\n messenger,\n transaction: transactions[0],\n })),\n is7702: false,\n usedBatch: false,\n };\n}\n\n/**\n * Estimate the source-chain gas for a quote's transactions, including the\n * transactions prepended at submit time.\n *\n * Post-quote flows prepend the original transaction, so it is estimated with\n * the quote transactions to let batch estimation detect EIP-7702 support.\n * Without it a single quote step is estimated alone, gets `is7702: false`, and\n * the batch falls back to separate transactions that each need native gas.\n * When the original transaction cannot be estimated, fixed allowances for the\n * prepended transactions are added instead.\n *\n * @param options - Options bag.\n * @param options.fromOverride - Address to estimate from instead of each\n * transaction's own `from`, such as the Predict Safe holding the source token.\n * @param options.messenger - Controller messenger.\n * @param options.request - Quote request.\n * @param options.transaction - Original transaction metadata.\n * @param options.transactions - Quote transactions to estimate.\n * @returns Source gas, with per-transaction limits in submission order.\n */\nexport async function estimateSourceGas({\n fromOverride,\n messenger,\n request,\n transaction,\n transactions,\n}: {\n fromOverride?: Hex;\n messenger: TransactionPayControllerMessenger;\n request: QuoteRequest;\n transaction: TransactionMeta;\n transactions: QuoteGasTransaction[];\n}): Promise<SourceGas> {\n const originalTransaction = getOriginalTransactionGas(request, transaction);\n\n const allTransactions = (\n originalTransaction ? [originalTransaction, ...transactions] : transactions\n ).map((singleTransaction) =>\n fromOverride\n ? { ...singleTransaction, from: fromOverride, gas: undefined }\n : singleTransaction,\n );\n\n const result = await estimateQuoteGasLimits({\n fallbackGas: getFeatureFlags(messenger).relayFallbackGas,\n fallbackOnSimulationFailure: true,\n messenger,\n transactions: allTransactions,\n });\n\n const gas = {\n gasLimits: result.gasLimits.map((gasLimit) => gasLimit.max),\n is7702: result.is7702,\n totalGasEstimate: result.totalGasEstimate,\n totalGasLimit: result.totalGasLimit,\n };\n\n return originalTransaction ? gas : addPrependedGas(gas, request, transaction);\n}\n\nasync function estimateQuoteGasLimitsBatch(\n transactions: QuoteGasTransaction[],\n messenger: TransactionPayControllerMessenger,\n): Promise<{\n batchGasLimit?: QuoteGasLimit;\n gasLimits: QuoteGasLimit[];\n is7702: boolean;\n requiresAuthorizationList?: true;\n totalGasEstimate: number;\n totalGasLimit: number;\n}> {\n const [firstTransaction] = transactions;\n const gasBuffer = getGasBuffer(messenger, firstTransaction.chainId);\n\n const paramGasLimits = transactions.map((transaction) =>\n parseGasLimit(transaction.gas),\n );\n\n const { gasLimits, requiresAuthorizationList } = await messenger.call(\n 'TransactionController:estimateGasBatch',\n {\n chainId: firstTransaction.chainId,\n from: firstTransaction.from,\n transactions: transactions.map(toBatchTransactionParams),\n },\n );\n\n if (gasLimits.length !== 1 && gasLimits.length !== transactions.length) {\n throw new Error('Unexpected batch gas limit count');\n }\n\n const bufferedGasLimits = gasLimits.map((gasLimit, index) => {\n const providedGasLimit = paramGasLimits[index];\n const providedGasWasPreserved =\n providedGasLimit !== undefined && providedGasLimit === gasLimit;\n\n // Per-entry batch results currently preserve validated input gas values\n // for transactions that already provided gas. If that contract changes\n // and batch estimation returns a different value, treat it as a fresh\n // estimate and apply the buffer. A single combined 7702 result is always\n // buffered because it is a fresh batch estimate.\n const useBuffer = gasLimits.length === 1 || !providedGasWasPreserved;\n const bufferedGas = Math.ceil(gasLimit * (useBuffer ? gasBuffer : 1));\n\n return {\n estimate: bufferedGas,\n max: bufferedGas,\n };\n });\n\n const totalGasLimit = bufferedGasLimits.reduce(\n (acc, gasLimit) => acc + gasLimit.max,\n 0,\n );\n const is7702 = bufferedGasLimits.length === 1;\n const batchGasLimit = is7702 ? bufferedGasLimits[0] : undefined;\n\n return {\n ...(batchGasLimit ? { batchGasLimit } : {}),\n gasLimits: bufferedGasLimits,\n is7702,\n ...(requiresAuthorizationList ? { requiresAuthorizationList } : {}),\n totalGasEstimate: totalGasLimit,\n totalGasLimit,\n };\n}\n\nasync function estimateQuoteGasLimitSingle({\n fallbackGas,\n fallbackOnSimulationFailure,\n messenger,\n transaction,\n}: {\n fallbackGas?: {\n estimate: number;\n max: number;\n };\n fallbackOnSimulationFailure: boolean;\n messenger: TransactionPayControllerMessenger;\n transaction: QuoteGasTransaction;\n}): Promise<{\n gasLimits: QuoteGasLimit[];\n totalGasEstimate: number;\n totalGasLimit: number;\n}> {\n const providedGasLimit = parseGasLimit(transaction.gas);\n\n if (providedGasLimit !== undefined) {\n log('Using provided gas limit', {\n chainId: transaction.chainId,\n gas: providedGasLimit,\n index: 0,\n to: transaction.to,\n });\n\n return {\n gasLimits: [\n {\n estimate: providedGasLimit,\n max: providedGasLimit,\n },\n ],\n totalGasEstimate: providedGasLimit,\n totalGasLimit: providedGasLimit,\n };\n }\n\n const gasLimitResult = await estimateGasLimit({\n chainId: transaction.chainId,\n data: transaction.data,\n fallbackGas,\n fallbackOnSimulationFailure,\n from: transaction.from,\n messenger,\n to: transaction.to,\n value: toHex(transaction.value ?? '0'),\n });\n\n if (gasLimitResult.usedFallback) {\n log('Gas estimate failed, using fallback', {\n chainId: transaction.chainId,\n error: gasLimitResult.error,\n index: 0,\n to: transaction.to,\n });\n }\n\n const gasLimit = {\n estimate: gasLimitResult.estimate,\n max: gasLimitResult.max,\n };\n\n return {\n gasLimits: [gasLimit],\n totalGasEstimate: gasLimit.estimate,\n totalGasLimit: gasLimit.max,\n };\n}\n\nfunction toBatchTransactionParams(\n transaction: QuoteGasTransaction,\n): BatchTransactionParams {\n return {\n data: transaction.data,\n gas: transaction.gas === undefined ? undefined : toHex(transaction.gas),\n maxFeePerGas: undefined,\n maxPriorityFeePerGas: undefined,\n to: transaction.to,\n value: toHex(transaction.value ?? '0'),\n };\n}\n\nfunction parseGasLimit(gas?: number | string): number | undefined {\n if (gas === undefined) {\n return undefined;\n }\n\n const parsedGas = new BigNumber(gas);\n\n if (\n !parsedGas.isFinite() ||\n parsedGas.isNaN() ||\n !parsedGas.isInteger() ||\n parsedGas.lte(0)\n ) {\n return undefined;\n }\n\n return parsedGas.toNumber();\n}\n\nfunction getOriginalTransactionGas(\n request: QuoteRequest,\n transaction: TransactionMeta,\n): QuoteGasTransaction | undefined {\n const { txParams } = transaction;\n const to = txParams.to as Hex | undefined;\n\n if (!request.isPostQuote || !to || hasAccountOverride(request, transaction)) {\n return undefined;\n }\n\n const gas = getOriginalGas(transaction);\n\n return {\n chainId: transaction.chainId,\n data: (txParams.data as Hex) ?? '0x',\n from: txParams.from as Hex,\n gas: gas ? String(gas) : undefined,\n to,\n value: txParams.value ?? '0',\n };\n}\n\nfunction addPrependedGas(\n gas: SourceGas,\n request: QuoteRequest,\n transaction: TransactionMeta,\n): SourceGas {\n const originalGas = request.isPostQuote\n ? getOriginalGas(transaction)\n : undefined;\n\n const withOriginal = originalGas\n ? prependGas(gas, new BigNumber(originalGas).toNumber())\n : gas;\n\n return request.paymentOverride\n ? prependGas(withOriginal, PAYMENT_OVERRIDE_GAS)\n : withOriginal;\n}\n\nfunction prependGas(gas: SourceGas, prependedGas: number): SourceGas {\n // A combined 7702 limit stays a single limit, otherwise the prepended\n // transaction gets its own limit ahead of the quote transactions.\n const gasLimits = gas.is7702\n ? [gas.gasLimits[0] + prependedGas]\n : [prependedGas, ...gas.gasLimits];\n\n log('Added prepended transaction gas', { gasLimits, prependedGas });\n\n return {\n gasLimits,\n is7702: gas.is7702,\n totalGasEstimate: gas.totalGasEstimate + prependedGas,\n totalGasLimit: gas.totalGasLimit + prependedGas,\n };\n}\n\n// Prefer the caller-provided nested gas, since the transaction controller may\n// re-estimate `txParams.gas` during batch creation.\nfunction getOriginalGas(transaction: TransactionMeta): string | undefined {\n return (\n transaction.nestedTransactions?.find((nested) => nested.gas)?.gas ??\n transaction.txParams.gas\n );\n}\n\nfunction hasAccountOverride(\n request: QuoteRequest,\n transaction: TransactionMeta,\n): boolean {\n return (\n request.from.toLowerCase() !==\n (transaction.txParams.from as Hex).toLowerCase()\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/transaction-pay-controller",
|
|
3
|
-
"version": "30.1.0-preview-
|
|
3
|
+
"version": "30.1.0-preview-eefc6963e",
|
|
4
4
|
"description": "Manages alternate payment strategies to provide required funds for transactions in MetaMask",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|
|
@@ -54,12 +54,12 @@
|
|
|
54
54
|
"@ethersproject/abi": "^5.7.0",
|
|
55
55
|
"@ethersproject/contracts": "^5.7.0",
|
|
56
56
|
"@ethersproject/providers": "^5.8.0",
|
|
57
|
-
"@metamask/accounts-controller": "^40.
|
|
57
|
+
"@metamask/accounts-controller": "^40.1.0",
|
|
58
58
|
"@metamask/assets-controller": "^19.0.0",
|
|
59
59
|
"@metamask/base-controller": "^10.0.0",
|
|
60
60
|
"@metamask/controller-utils": "^13.0.0",
|
|
61
61
|
"@metamask/gas-fee-controller": "^27.0.0",
|
|
62
|
-
"@metamask/keyring-controller": "^28.
|
|
62
|
+
"@metamask/keyring-controller": "^28.2.0",
|
|
63
63
|
"@metamask/messenger": "^3.0.0",
|
|
64
64
|
"@metamask/metamask-eth-abis": "^3.1.1",
|
|
65
65
|
"@metamask/network-controller": "^37.0.1",
|