mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Ensure that eth_estimateGas is called to estimate gas limit for simple sends on custom networks (#11418)
* Ensure that eth_estimateGas is called to estimate gas limit for simple sends on custom networks * getIsNonStandardEthChain returns false when in test * Add comment explaining gas limit buffer multipliers in estimateGasLimitForSend
This commit is contained in:
parent
9889d070cd
commit
a60301686c
ui
@ -37,6 +37,7 @@ import {
|
|||||||
getIsMainnet,
|
getIsMainnet,
|
||||||
getSelectedAddress,
|
getSelectedAddress,
|
||||||
getTargetAccount,
|
getTargetAccount,
|
||||||
|
getIsNonStandardEthChain,
|
||||||
} from '../../selectors';
|
} from '../../selectors';
|
||||||
import {
|
import {
|
||||||
displayWarning,
|
displayWarning,
|
||||||
@ -174,8 +175,11 @@ async function estimateGasLimitForSend({
|
|||||||
sendToken,
|
sendToken,
|
||||||
to,
|
to,
|
||||||
data,
|
data,
|
||||||
|
isNonStandardEthChain,
|
||||||
...options
|
...options
|
||||||
}) {
|
}) {
|
||||||
|
let isSimpleSendOnNonStandardNetwork = false;
|
||||||
|
|
||||||
// blockGasLimit may be a falsy, but defined, value when we receive it from
|
// blockGasLimit may be a falsy, but defined, value when we receive it from
|
||||||
// state, so we use logical or to fall back to MIN_GAS_LIMIT_HEX.
|
// state, so we use logical or to fall back to MIN_GAS_LIMIT_HEX.
|
||||||
const blockGasLimit = options.blockGasLimit || MIN_GAS_LIMIT_HEX;
|
const blockGasLimit = options.blockGasLimit || MIN_GAS_LIMIT_HEX;
|
||||||
@ -211,8 +215,10 @@ async function estimateGasLimitForSend({
|
|||||||
// Geth will return '0x', and ganache-core v2.2.1 will return '0x0'
|
// Geth will return '0x', and ganache-core v2.2.1 will return '0x0'
|
||||||
const contractCodeIsEmpty =
|
const contractCodeIsEmpty =
|
||||||
!contractCode || contractCode === '0x' || contractCode === '0x0';
|
!contractCode || contractCode === '0x' || contractCode === '0x0';
|
||||||
if (contractCodeIsEmpty) {
|
if (contractCodeIsEmpty && !isNonStandardEthChain) {
|
||||||
return GAS_LIMITS.SIMPLE;
|
return GAS_LIMITS.SIMPLE;
|
||||||
|
} else if (contractCodeIsEmpty && isNonStandardEthChain) {
|
||||||
|
isSimpleSendOnNonStandardNetwork = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,17 +237,33 @@ async function estimateGasLimitForSend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we do not yet have a gasLimit, we must call into our background
|
if (!isSimpleSendOnNonStandardNetwork) {
|
||||||
// process to get an estimate for gasLimit based on known parameters.
|
// If we do not yet have a gasLimit, we must call into our background
|
||||||
|
// process to get an estimate for gasLimit based on known parameters.
|
||||||
|
|
||||||
|
paramsForGasEstimate.gas = addHexPrefix(
|
||||||
|
multiplyCurrencies(blockGasLimit, 0.95, {
|
||||||
|
multiplicandBase: 16,
|
||||||
|
multiplierBase: 10,
|
||||||
|
roundDown: '0',
|
||||||
|
toNumericBase: 'hex',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The buffer multipler reduces transaction failures by ensuring that the
|
||||||
|
// estimated gas is always sufficient. Without the multiplier, estimates
|
||||||
|
// for contract interactions can become inaccurate over time. This is because
|
||||||
|
// gas estimation is non-deterministic. The gas required for the exact same
|
||||||
|
// transaction call can change based on state of a contract or changes in the
|
||||||
|
// contracts environment (blockchain data or contracts it interacts with).
|
||||||
|
// Applying the 1.5 buffer has proven to be a useful guard against this non-
|
||||||
|
// deterministic behaviour.
|
||||||
|
//
|
||||||
|
// Gas estimation of simple sends should, however, be deterministic. As such
|
||||||
|
// no buffer is needed in those cases.
|
||||||
|
const bufferMultiplier = isSimpleSendOnNonStandardNetwork ? 1 : 1.5;
|
||||||
|
|
||||||
paramsForGasEstimate.gas = addHexPrefix(
|
|
||||||
multiplyCurrencies(blockGasLimit, 0.95, {
|
|
||||||
multiplicandBase: 16,
|
|
||||||
multiplierBase: 10,
|
|
||||||
roundDown: '0',
|
|
||||||
toNumericBase: 'hex',
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
try {
|
try {
|
||||||
// call into the background process that will simulate transaction
|
// call into the background process that will simulate transaction
|
||||||
// execution on the node and return an estimate of gasLimit
|
// execution on the node and return an estimate of gasLimit
|
||||||
@ -249,7 +271,7 @@ async function estimateGasLimitForSend({
|
|||||||
const estimateWithBuffer = addGasBuffer(
|
const estimateWithBuffer = addGasBuffer(
|
||||||
estimatedGasLimit,
|
estimatedGasLimit,
|
||||||
blockGasLimit,
|
blockGasLimit,
|
||||||
1.5,
|
bufferMultiplier,
|
||||||
);
|
);
|
||||||
return addHexPrefix(estimateWithBuffer);
|
return addHexPrefix(estimateWithBuffer);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -303,7 +325,9 @@ export async function getERC20Balance(token, accountAddress) {
|
|||||||
export const computeEstimatedGasLimit = createAsyncThunk(
|
export const computeEstimatedGasLimit = createAsyncThunk(
|
||||||
'send/computeEstimatedGasLimit',
|
'send/computeEstimatedGasLimit',
|
||||||
async (_, thunkApi) => {
|
async (_, thunkApi) => {
|
||||||
const { send, metamask } = thunkApi.getState();
|
const state = thunkApi.getState();
|
||||||
|
const { send, metamask } = state;
|
||||||
|
const isNonStandardEthChain = getIsNonStandardEthChain(state);
|
||||||
if (send.stage !== SEND_STAGES.EDIT) {
|
if (send.stage !== SEND_STAGES.EDIT) {
|
||||||
const gasLimit = await estimateGasLimitForSend({
|
const gasLimit = await estimateGasLimitForSend({
|
||||||
gasPrice: send.gas.gasPrice,
|
gasPrice: send.gas.gasPrice,
|
||||||
@ -313,6 +337,7 @@ export const computeEstimatedGasLimit = createAsyncThunk(
|
|||||||
to: send.recipient.address?.toLowerCase(),
|
to: send.recipient.address?.toLowerCase(),
|
||||||
value: send.amount.value,
|
value: send.amount.value,
|
||||||
data: send.draftTransaction.userInputHexData,
|
data: send.draftTransaction.userInputHexData,
|
||||||
|
isNonStandardEthChain,
|
||||||
});
|
});
|
||||||
await thunkApi.dispatch(setCustomGasLimit(gasLimit));
|
await thunkApi.dispatch(setCustomGasLimit(gasLimit));
|
||||||
return {
|
return {
|
||||||
@ -337,6 +362,7 @@ export const initializeSendState = createAsyncThunk(
|
|||||||
'send/initializeSendState',
|
'send/initializeSendState',
|
||||||
async (_, thunkApi) => {
|
async (_, thunkApi) => {
|
||||||
const state = thunkApi.getState();
|
const state = thunkApi.getState();
|
||||||
|
const isNonStandardEthChain = getIsNonStandardEthChain(state);
|
||||||
const {
|
const {
|
||||||
send: { asset, stage, recipient, amount, draftTransaction },
|
send: { asset, stage, recipient, amount, draftTransaction },
|
||||||
metamask,
|
metamask,
|
||||||
@ -383,6 +409,7 @@ export const initializeSendState = createAsyncThunk(
|
|||||||
to: recipient.address.toLowerCase(),
|
to: recipient.address.toLowerCase(),
|
||||||
value: amount.value,
|
value: amount.value,
|
||||||
data: draftTransaction.userInputHexData,
|
data: draftTransaction.userInputHexData,
|
||||||
|
isNonStandardEthChain,
|
||||||
});
|
});
|
||||||
gasLimit = estimatedGasLimit || gasLimit;
|
gasLimit = estimatedGasLimit || gasLimit;
|
||||||
}
|
}
|
||||||
|
@ -1113,6 +1113,9 @@ describe('Send Slice', () => {
|
|||||||
metamask: {
|
metamask: {
|
||||||
blockGasLimit: '',
|
blockGasLimit: '',
|
||||||
selectedAddress: '',
|
selectedAddress: '',
|
||||||
|
provider: {
|
||||||
|
chainId: '0x1',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
...defaultSendAmountState.send,
|
...defaultSendAmountState.send,
|
||||||
send: {
|
send: {
|
||||||
@ -1160,6 +1163,9 @@ describe('Send Slice', () => {
|
|||||||
metamask: {
|
metamask: {
|
||||||
blockGasLimit: '',
|
blockGasLimit: '',
|
||||||
selectedAddress: '',
|
selectedAddress: '',
|
||||||
|
provider: {
|
||||||
|
chainId: '0x1',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
send: {
|
send: {
|
||||||
account: {
|
account: {
|
||||||
@ -1372,6 +1378,9 @@ describe('Send Slice', () => {
|
|||||||
metamask: {
|
metamask: {
|
||||||
blockGasLimit: '',
|
blockGasLimit: '',
|
||||||
selectedAddress: '',
|
selectedAddress: '',
|
||||||
|
provider: {
|
||||||
|
chainId: '0x1',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
send: {
|
send: {
|
||||||
account: {
|
account: {
|
||||||
|
@ -376,6 +376,10 @@ export function getIsTestnet(state) {
|
|||||||
return TEST_CHAINS.includes(chainId);
|
return TEST_CHAINS.includes(chainId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getIsNonStandardEthChain(state) {
|
||||||
|
return !(getIsMainnet(state) || getIsTestnet(state) || process.env.IN_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
export function getPreferences({ metamask }) {
|
export function getPreferences({ metamask }) {
|
||||||
return metamask.preferences;
|
return metamask.preferences;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user