Skip to content

Commit 5d4a7c1

Browse files
committed
fix: include gas in simulation requests (#5754)
Include gas limit and gas fees in balance change simulation requests. Specifically: - Create alternate simulation request specifically for gas fee tokens in new `utils/gas-fee-tokens.ts`. - Rename `utils/simulation.ts` to `utils/balance-changes.ts`. - Add `withGas` and `withDefaultBlockOverrides` to balance change simulation requests. - Override balance in balance change requests if insufficient balance. - Subtract gas cost from native balance change. - Replace code override with `authorizationList` including `from` property. - Retrieve MetaMask fee from simulation API. - [x] I've updated the test suite for new or updated code as appropriate - [x] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/contributing.md#updating-changelogs), highlighting breaking changes as necessary - [x] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes
1 parent 667d223 commit 5d4a7c1

File tree

8 files changed

+981
-713
lines changed

8 files changed

+981
-713
lines changed

packages/transaction-controller/src/TransactionController.test.ts

Lines changed: 60 additions & 226 deletions
Large diffs are not rendered by default.

packages/transaction-controller/src/TransactionController.ts

Lines changed: 31 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import {
5151
JsonRpcError,
5252
} from '@metamask/rpc-errors';
5353
import type { Hex, Json } from '@metamask/utils';
54-
import { add0x, hexToNumber, remove0x } from '@metamask/utils';
54+
import { add0x, hexToNumber } from '@metamask/utils';
5555
// This package purposefully relies on Node's EventEmitter module.
5656
// eslint-disable-next-line import-x/no-nodejs-modules
5757
import { EventEmitter } from 'events';
@@ -124,22 +124,16 @@ import {
124124
SimulationErrorCode,
125125
GasFeeEstimateLevel,
126126
} from './types';
127+
import { getBalanceChanges } from './utils/balance-changes';
128+
import { addTransactionBatch, isAtomicBatchSupported } from './utils/batch';
127129
import {
128-
addTransactionBatch,
129-
ERROR_MESSAGE_NO_UPGRADE_CONTRACT,
130-
isAtomicBatchSupported,
131-
} from './utils/batch';
132-
import {
133-
DELEGATION_PREFIX,
134-
doesChainSupportEIP7702,
135-
ERROR_MESSGE_PUBLIC_KEY,
136130
generateEIP7702BatchTransaction,
137131
getDelegationAddress,
138132
signAuthorizationList,
139133
} from './utils/eip7702';
140134
import { validateConfirmedExternalTransaction } from './utils/external-transactions';
141-
import { getEIP7702UpgradeContractAddress } from './utils/feature-flags';
142135
import { addGasBuffer, estimateGas, updateGas } from './utils/gas';
136+
import { getGasFeeTokens } from './utils/gas-fee-tokens';
143137
import { updateGasFees } from './utils/gas-fees';
144138
import { getGasFeeFlow } from './utils/gas-flow';
145139
import {
@@ -156,8 +150,6 @@ import {
156150
} from './utils/nonce';
157151
import { prepareTransaction, serializeTransaction } from './utils/prepare';
158152
import { getTransactionParamsWithIncreasedGasFee } from './utils/retry';
159-
import type { GetSimulationDataRequest } from './utils/simulation';
160-
import { getSimulationData } from './utils/simulation';
161153
import {
162154
updatePostTransactionBalance,
163155
updateSwapsTransaction,
@@ -4031,8 +4023,14 @@ export class TransactionController extends BaseController<
40314023
traceContext?: TraceContext;
40324024
} = {},
40334025
) {
4034-
const { id: transactionId, simulationData: prevSimulationData } =
4035-
transactionMeta;
4026+
const {
4027+
chainId,
4028+
id: transactionId,
4029+
nestedTransactions,
4030+
networkClientId,
4031+
simulationData: prevSimulationData,
4032+
txParams,
4033+
} = transactionMeta;
40364034

40374035
let simulationData: SimulationData = {
40384036
error: {
@@ -4045,14 +4043,17 @@ export class TransactionController extends BaseController<
40454043
let gasFeeTokens: GasFeeToken[] = [];
40464044

40474045
if (this.#isSimulationEnabled()) {
4048-
const result = await this.#getSimulationData({
4049-
blockTime,
4050-
traceContext,
4051-
transactionMeta,
4052-
});
4053-
4054-
gasFeeTokens = result?.gasFeeTokens;
4055-
simulationData = result?.simulationData;
4046+
simulationData = await this.#trace(
4047+
{ name: 'Simulate', parentContext: traceContext },
4048+
() =>
4049+
getBalanceChanges({
4050+
blockTime,
4051+
chainId,
4052+
ethQuery: this.#getEthQuery({ networkClientId }),
4053+
nestedTransactions,
4054+
txParams,
4055+
}),
4056+
);
40564057

40574058
if (
40584059
blockTime &&
@@ -4064,6 +4065,14 @@ export class TransactionController extends BaseController<
40644065
isUpdatedAfterSecurityCheck: true,
40654066
};
40664067
}
4068+
4069+
gasFeeTokens = await getGasFeeTokens({
4070+
chainId,
4071+
isEIP7702GasFeeTokensEnabled: this.#isEIP7702GasFeeTokensEnabled,
4072+
messenger: this.messagingSystem,
4073+
publicKeyEIP7702: this.#publicKeyEIP7702,
4074+
transactionMeta,
4075+
});
40674076
}
40684077

40694078
const finalTransactionMeta = this.#getTransaction(transactionId);
@@ -4281,100 +4290,4 @@ export class TransactionController extends BaseController<
42814290
newTransactionMeta,
42824291
);
42834292
}
4284-
4285-
async #getSimulationData({
4286-
blockTime,
4287-
traceContext,
4288-
transactionMeta,
4289-
}: {
4290-
blockTime?: number;
4291-
traceContext?: TraceContext;
4292-
transactionMeta: TransactionMeta;
4293-
}) {
4294-
const { chainId, delegationAddress, txParams } = transactionMeta;
4295-
4296-
const {
4297-
authorizationList: authorizationListRequest,
4298-
data,
4299-
from,
4300-
to,
4301-
value,
4302-
} = txParams;
4303-
4304-
const authorizationAddress = authorizationListRequest?.[0]?.address;
4305-
4306-
const senderCode =
4307-
authorizationAddress &&
4308-
((DELEGATION_PREFIX + remove0x(authorizationAddress)) as Hex);
4309-
4310-
const is7702GasFeeTokensEnabled =
4311-
await this.#isEIP7702GasFeeTokensEnabled(transactionMeta);
4312-
4313-
const use7702Fees =
4314-
is7702GasFeeTokensEnabled &&
4315-
doesChainSupportEIP7702(chainId, this.messagingSystem);
4316-
4317-
let authorizationList:
4318-
| GetSimulationDataRequest['authorizationList']
4319-
| undefined = authorizationListRequest?.map((authorization) => ({
4320-
address: authorization.address,
4321-
from: from as Hex,
4322-
}));
4323-
4324-
if (use7702Fees && !delegationAddress && !authorizationList) {
4325-
authorizationList = this.#getSimulationAuthorizationList({
4326-
chainId,
4327-
from: from as Hex,
4328-
});
4329-
}
4330-
4331-
return await this.#trace(
4332-
{ name: 'Simulate', parentContext: traceContext },
4333-
() =>
4334-
getSimulationData(
4335-
{
4336-
authorizationList,
4337-
chainId,
4338-
data: data as Hex,
4339-
from: from as Hex,
4340-
to: to as Hex,
4341-
value: value as Hex,
4342-
},
4343-
{
4344-
blockTime,
4345-
senderCode,
4346-
use7702Fees,
4347-
},
4348-
),
4349-
);
4350-
}
4351-
4352-
#getSimulationAuthorizationList({
4353-
chainId,
4354-
from,
4355-
}: {
4356-
chainId: Hex;
4357-
from: Hex;
4358-
}): GetSimulationDataRequest['authorizationList'] | undefined {
4359-
if (!this.#publicKeyEIP7702) {
4360-
throw rpcErrors.internal(ERROR_MESSGE_PUBLIC_KEY);
4361-
}
4362-
4363-
const upgradeAddress = getEIP7702UpgradeContractAddress(
4364-
chainId,
4365-
this.messagingSystem,
4366-
this.#publicKeyEIP7702,
4367-
);
4368-
4369-
if (!upgradeAddress) {
4370-
throw rpcErrors.internal(ERROR_MESSAGE_NO_UPGRADE_CONTRACT);
4371-
}
4372-
4373-
return [
4374-
{
4375-
address: upgradeAddress,
4376-
from: from as Hex,
4377-
},
4378-
];
4379-
}
43804293
}

packages/transaction-controller/src/api/simulation-api.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,6 @@ export type SimulationRequestTransaction = {
4444

4545
/** Request to the simulation API to simulate transactions. */
4646
export type SimulationRequest = {
47-
/**
48-
* Transactions to be sequentially simulated.
49-
* State changes impact subsequent transactions in the list.
50-
*/
51-
transactions: SimulationRequestTransaction[];
52-
5347
blockOverrides?: {
5448
time?: Hex;
5549
};
@@ -83,12 +77,30 @@ export type SimulationRequest = {
8377
withTransfer?: boolean;
8478
};
8579

80+
/**
81+
* Transactions to be sequentially simulated.
82+
* State changes impact subsequent transactions in the list.
83+
*/
84+
transactions: SimulationRequestTransaction[];
85+
8686
/**
8787
* Whether to include call traces in the response.
8888
* Defaults to false.
8989
*/
9090
withCallTrace?: boolean;
9191

92+
/**
93+
* Whether to include the default block data in the simulation.
94+
* Defaults to false.
95+
*/
96+
withDefaultBlockOverrides?: boolean;
97+
98+
/**
99+
* Whether to use the gas fees in the simulation.
100+
* Defaults to false.
101+
*/
102+
withGas?: boolean;
103+
92104
/**
93105
* Whether to include event logs in the response.
94106
* Defaults to false.
@@ -161,6 +173,9 @@ export type SimulationResponseTokenFee = {
161173
/** Conversation rate of 1 token to native WEI. */
162174
rateWei: Hex;
163175

176+
/** Portion of `balanceNeededToken` that is the fee paid to MetaMask. */
177+
serviceFee?: Hex;
178+
164179
/** Estimated gas limit required for fee transfer. */
165180
transferEstimate: Hex;
166181
};
@@ -188,6 +203,12 @@ export type SimulationResponseTransaction = {
188203
tokenFees: SimulationResponseTokenFee[];
189204
}[];
190205

206+
/**
207+
* Estimated total gas cost of the transaction.
208+
* Included in the stateDiff if `withGas` is true.
209+
*/
210+
gasCost?: number;
211+
191212
/** Required `gasLimit` for the transaction. */
192213
gasLimit?: Hex;
193214

packages/transaction-controller/src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,9 @@ export type GasFeeToken = {
17231723
/** Decimals of the token. */
17241724
decimals: number;
17251725

1726+
/** Portion of the amount that is the fee paid to MetaMask. */
1727+
fee?: Hex;
1728+
17261729
/** Estimated gas limit required for original transaction. */
17271730
gas: Hex;
17281731

0 commit comments

Comments
 (0)