@@ -96,6 +96,7 @@ import {
9696 FeePaymentOption ,
9797 FullEstimationSummary
9898} from '../../libs/estimate/interfaces'
99+ import { calculateFeeAmount } from '../../libs/fees/fees'
99100import { humanizeAccountOp } from '../../libs/humanizer'
100101import { HumanizerWarning , IrCall } from '../../libs/humanizer/interfaces'
101102import { hasRelayerSupport , relayerAdditionalNetworks } from '../../libs/networks/networks'
@@ -201,6 +202,7 @@ export const noStateUpdateStatuses = [
201202export type SignAccountOpUpdateProps = {
202203 gasPrices ?: GasSpeeds
203204 customGasPrices ?: GasSpeeds
205+ customGasLimit ?: bigint
204206 feeToken ?: TokenResult
205207 paidBy ?: string
206208 paidByKeyType ?: Key [ 'type' ]
@@ -260,6 +262,8 @@ export class SignAccountOpController extends EventEmitter implements ISignAccoun
260262
261263 hasCustomGasPrices : boolean = false
262264
265+ customGasLimit ?: bigint
266+
263267 feeSpeeds : {
264268 [ identifier : string ] : SpeedCalc [ ]
265269 } = { }
@@ -1234,6 +1238,7 @@ export class SignAccountOpController extends EventEmitter implements ISignAccoun
12341238 update ( {
12351239 gasPrices,
12361240 customGasPrices,
1241+ customGasLimit,
12371242 feeToken,
12381243 paidBy,
12391244 speed,
@@ -1390,6 +1395,10 @@ export class SignAccountOpController extends EventEmitter implements ISignAccoun
13901395 this . gasPrices = gasPrices
13911396 }
13921397
1398+ if ( typeof customGasLimit !== 'undefined' ) {
1399+ this . customGasLimit = customGasLimit
1400+ }
1401+
13931402 this . #syncSpeedUpFeeSelectionFromEstimation( )
13941403
13951404 if ( feeToken && paidBy && ! isSpeedUpTransaction ) {
@@ -1461,6 +1470,7 @@ export class SignAccountOpController extends EventEmitter implements ISignAccoun
14611470 Array . isArray ( accountOpData ?. calls ) ||
14621471 gasPrices ||
14631472 customGasPrices ||
1473+ typeof customGasLimit !== 'undefined' ||
14641474 this . #paidBy ||
14651475 this . feeTokenResult ||
14661476 hasNewEstimation
@@ -1754,38 +1764,6 @@ export class SignAccountOpController extends EventEmitter implements ISignAccoun
17541764 return BigInt ( toBigInt )
17551765 }
17561766
1757- static getAmountAfterFeeTokenConvert (
1758- simulatedGasLimit : bigint ,
1759- gasPrice : bigint ,
1760- nativeRatio : bigint ,
1761- feeTokenDecimals : number ,
1762- addedNative : bigint
1763- ) {
1764- const amountInWei = simulatedGasLimit * gasPrice + addedNative
1765-
1766- // Let's break down the process of converting the amount into FeeToken:
1767- // 1. Initially, we multiply the amount in wei by the native to fee token ratio.
1768- // 2. Next, we address the decimal places:
1769- // 2.1. First, we convert wei to native by dividing by 10^18 (representing the decimals).
1770- // 2.2. Now, with the amount in the native token, we incorporate nativeRatio decimals into the calculation (18 + 18) to standardize the amount.
1771- // 2.3. At this point, we precisely determine the number of fee tokens. For instance, if the amount is 3 USDC, we must convert it to a BigInt value, while also considering feeToken.decimals.
1772- const extraDecimals = BigInt ( 10 ** 18 )
1773- const feeTokenExtraDecimals = BigInt ( 10 ** ( 18 - feeTokenDecimals ) )
1774- const pow = extraDecimals * feeTokenExtraDecimals
1775- const result = ( amountInWei * nativeRatio ) / pow
1776-
1777- // Fixes the edge case where the fee in wei is not zero
1778- // but the decimals of the token we are converting to
1779- // cannot represent the amount in wei. Example: 0.(6zeros)1 USDC
1780- // We are returning 1n which is the smallest possible amount
1781- // to be represented in USDC
1782- if ( result === 0n && amountInWei !== 0n ) {
1783- return 1n
1784- }
1785-
1786- return result
1787- }
1788-
17891767 async #traceCall( ) {
17901768 // `traceCall` should not be invoked too frequently. However, if there is a pending timeout,
17911769 // it should be cleared to prevent the previous interval from changing the status
@@ -1880,15 +1858,6 @@ export class SignAccountOpController extends EventEmitter implements ISignAccoun
18801858 clearTimeout ( timeoutId )
18811859 }
18821860
1883- /**
1884- * Increase the paymaster fee by 10%, the relayer by 5%.
1885- * This is required because even now, we are broadcasting at a loss
1886- */
1887- #increaseFee( amount : bigint , broadcaster : string = 'relayer' ) : bigint {
1888- if ( broadcaster === 'paymaster' ) return amount + amount / 10n
1889- return amount + amount / 20n
1890- }
1891-
18921861 #addExtra( gasInWei : bigint , percentageIncrease : bigint ) : Hex {
18931862 const percent = 100n / percentageIncrease
18941863 return toBeHex ( gasInWei + gasInWei / percent ) as Hex
@@ -2009,23 +1978,18 @@ export class SignAccountOpController extends EventEmitter implements ISignAccoun
20091978 let simulatedGasLimit : bigint
20101979 let gasPrice
20111980 let maxPriorityFeePerGas
1981+ let amountGasPrice : bigint
1982+ let usesPaymaster = false
20121983
20131984 if ( broadcastOption === BROADCAST_OPTIONS . byBundler ) {
20141985 if ( ! estimation . bundlerEstimation ) return
20151986
2016- const usesPaymaster = estimation . bundlerEstimation ?. paymaster . isUsable ( )
1987+ usesPaymaster = ! ! estimation . bundlerEstimation ?. paymaster . isUsable ( )
20171988 simulatedGasLimit =
20181989 BigInt ( gasUsed ) +
20191990 BigInt ( estimation . bundlerEstimation . preVerificationGas ) +
20201991 BigInt ( option . gasUsed )
2021- amount = SignAccountOpController . getAmountAfterFeeTokenConvert (
2022- simulatedGasLimit ,
2023- BigInt ( increasedPrices . maxFeePerGas ) ,
2024- nativeRatio ,
2025- option . token . decimals ,
2026- 0n
2027- )
2028- if ( usesPaymaster ) amount = this . #increaseFee( amount , 'paymaster' )
1992+ amountGasPrice = BigInt ( increasedPrices . maxFeePerGas )
20291993 gasPrice = BigInt ( receivedPrices . maxFeePerGas )
20301994 maxPriorityFeePerGas = BigInt ( receivedPrices . maxPriorityFeePerGas )
20311995 } else if (
@@ -2036,36 +2000,42 @@ export class SignAccountOpController extends EventEmitter implements ISignAccoun
20362000 simulatedGasLimit = gasUsed
20372001 gasPrice = BigInt ( increasedPrices . maxFeePerGas )
20382002 maxPriorityFeePerGas = BigInt ( increasedPrices . maxPriorityFeePerGas )
2003+ amountGasPrice = BigInt ( receivedPrices . maxFeePerGas )
20392004
20402005 this . accountOp . calls . forEach ( ( call ) => {
20412006 if ( call . to && getAddress ( call . to ) === SINGLETON ) {
20422007 simulatedGasLimit = getGasUsed ( simulatedGasLimit )
20432008 }
20442009 } )
2045-
2046- amount = simulatedGasLimit * BigInt ( receivedPrices . maxFeePerGas ) + option . addedNative
20472010 } else if ( broadcastOption === BROADCAST_OPTIONS . byOtherEOA ) {
20482011 // Smart account, but EOA pays the fee
20492012 // 7702, and it pays for the fee by itself
20502013 simulatedGasLimit = gasUsed
2051- amount = simulatedGasLimit * BigInt ( receivedPrices . maxFeePerGas ) + option . addedNative
20522014 gasPrice = BigInt ( increasedPrices . maxFeePerGas )
20532015 maxPriorityFeePerGas = BigInt ( increasedPrices . maxPriorityFeePerGas )
2016+ amountGasPrice = BigInt ( receivedPrices . maxFeePerGas )
20542017 } else {
20552018 // Relayer
20562019 simulatedGasLimit = gasUsed + option . gasUsed
2057- amount = SignAccountOpController . getAmountAfterFeeTokenConvert (
2058- simulatedGasLimit ,
2059- BigInt ( increasedPrices . maxFeePerGas ) ,
2060- nativeRatio ,
2061- option . token . decimals ,
2062- option . addedNative
2063- )
2064- amount = this . #increaseFee( amount )
2020+ amountGasPrice = BigInt ( increasedPrices . maxFeePerGas )
20652021 gasPrice = BigInt ( increasedPrices . maxFeePerGas )
20662022 maxPriorityFeePerGas = BigInt ( increasedPrices . maxPriorityFeePerGas )
20672023 }
20682024
2025+ if ( typeof this . customGasLimit !== 'undefined' ) {
2026+ simulatedGasLimit = this . customGasLimit
2027+ }
2028+
2029+ amount = calculateFeeAmount ( {
2030+ broadcastOption,
2031+ simulatedGasLimit,
2032+ gasPrice : amountGasPrice ,
2033+ nativeRatio,
2034+ feeTokenDecimals : option . token . decimals ,
2035+ addedNative : broadcastOption === BROADCAST_OPTIONS . byBundler ? 0n : option . addedNative ,
2036+ usesPaymaster
2037+ } )
2038+
20692039 const feeSpeed : SpeedCalc = {
20702040 type : speed ,
20712041 simulatedGasLimit,
@@ -2184,10 +2154,11 @@ export class SignAccountOpController extends EventEmitter implements ISignAccoun
21842154 inToken : this . feeTokenResult . address ,
21852155 feeTokenChainId : this . feeTokenResult . chainId ,
21862156 amount : chosenSpeed . amount ,
2187- simulatedGasLimit : chosenSpeed . simulatedGasLimit ,
2157+ simulatedGasLimit : this . customGasLimit ?? chosenSpeed . simulatedGasLimit ,
21882158 gasPrice : chosenSpeed . gasPrice ,
21892159 maxPriorityFeePerGas :
21902160 'maxPriorityFeePerGas' in chosenSpeed ? chosenSpeed . maxPriorityFeePerGas : undefined ,
2161+ isCustomGasLimit : typeof this . customGasLimit !== 'undefined' ,
21912162 broadcastOption : this . baseAccount . getBroadcastOption ( this . selectedOption , {
21922163 op : this . accountOp ,
21932164 isSponsored : this . isSponsored
@@ -3488,6 +3459,12 @@ export class SignAccountOpController extends EventEmitter implements ISignAccoun
34883459 return this . baseAccount . canSetCustomGasPrices ( this . selectedOption )
34893460 }
34903461
3462+ get canSetCustomGas ( ) : boolean {
3463+ if ( ! this . selectedOption ) return false
3464+
3465+ return this . baseAccount . canSetCustomGas ( this . selectedOption , this . accountOp )
3466+ }
3467+
34913468 get threshold ( ) : number {
34923469 const accountState =
34933470 this . #accounts. accountStates [ this . account . addr ] ! [ this . #network. chainId . toString ( ) ]
@@ -3528,6 +3505,7 @@ export class SignAccountOpController extends EventEmitter implements ISignAccoun
35283505 banners : this . banners ,
35293506 canAccountBroadcastByItself : this . canAccountBroadcastByItself ,
35303507 canSetCustomGasPrices : this . canSetCustomGasPrices ,
3508+ canSetCustomGas : this . canSetCustomGas ,
35313509 threshold : this . threshold ,
35323510 canBroadcast : this . canBroadcast ,
35333511 hasSafeApiFailed : this . hasSafeApiFailed
0 commit comments