@metamask-previews/transaction-controller 69.0.0-preview-3f3e1111c → 69.0.0-preview-1ed087802
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 +0 -5
- package/dist/gas-flows/MantleLayer1GasFeeFlow.cjs +6 -21
- package/dist/gas-flows/MantleLayer1GasFeeFlow.cjs.map +1 -1
- package/dist/gas-flows/MantleLayer1GasFeeFlow.d.cts.map +1 -1
- package/dist/gas-flows/MantleLayer1GasFeeFlow.d.mts.map +1 -1
- package/dist/gas-flows/MantleLayer1GasFeeFlow.mjs +6 -21
- package/dist/gas-flows/MantleLayer1GasFeeFlow.mjs.map +1 -1
- package/dist/gas-flows/OracleLayer1GasFeeFlow.cjs +20 -37
- package/dist/gas-flows/OracleLayer1GasFeeFlow.cjs.map +1 -1
- package/dist/gas-flows/OracleLayer1GasFeeFlow.d.cts +1 -1
- package/dist/gas-flows/OracleLayer1GasFeeFlow.d.cts.map +1 -1
- package/dist/gas-flows/OracleLayer1GasFeeFlow.d.mts +1 -1
- package/dist/gas-flows/OracleLayer1GasFeeFlow.d.mts.map +1 -1
- package/dist/gas-flows/OracleLayer1GasFeeFlow.mjs +20 -37
- package/dist/gas-flows/OracleLayer1GasFeeFlow.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +3 -3
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +3 -3
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/dist/utils/layer1-gas-fee-flow.cjs +6 -1
- package/dist/utils/layer1-gas-fee-flow.cjs.map +1 -1
- package/dist/utils/layer1-gas-fee-flow.d.cts.map +1 -1
- package/dist/utils/layer1-gas-fee-flow.d.mts.map +1 -1
- package/dist/utils/layer1-gas-fee-flow.mjs +6 -1
- package/dist/utils/layer1-gas-fee-flow.mjs.map +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,11 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
-
### Changed
|
|
11
|
-
|
|
12
|
-
- Query layer 1 gas fee oracles via direct `eth_call` RPC requests instead of an ethers `Contract` backed by `Web3Provider` ([#9505](https://github.com/MetaMask/core/pull/9505))
|
|
13
|
-
- `Web3Provider` schedules its JSON-RPC dispatch with `setTimeout`, which never fires on React Native iOS when the timer pump is starved, blocking `addTransaction` indefinitely and preventing dapp confirmations from appearing ([MetaMask/metamask-mobile#32863](https://github.com/MetaMask/metamask-mobile/issues/32863))
|
|
14
|
-
|
|
15
10
|
## [69.0.0]
|
|
16
11
|
|
|
17
12
|
### Changed
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MantleLayer1GasFeeFlow = void 0;
|
|
4
|
-
const
|
|
4
|
+
const contracts_1 = require("@ethersproject/contracts");
|
|
5
|
+
const providers_1 = require("@ethersproject/providers");
|
|
5
6
|
const constants_1 = require("../constants.cjs");
|
|
6
|
-
const provider_1 = require("../utils/provider.cjs");
|
|
7
7
|
const utils_1 = require("../utils/utils.cjs");
|
|
8
8
|
const OracleLayer1GasFeeFlow_1 = require("./OracleLayer1GasFeeFlow.cjs");
|
|
9
9
|
const MANTLE_CHAIN_IDS = [constants_1.CHAIN_IDS.MANTLE, constants_1.CHAIN_IDS.MANTLE_SEPOLIA];
|
|
@@ -22,7 +22,6 @@ const TOKEN_RATIO_ABI = [
|
|
|
22
22
|
type: 'function',
|
|
23
23
|
},
|
|
24
24
|
];
|
|
25
|
-
const TOKEN_RATIO_INTERFACE = new abi_1.Interface(TOKEN_RATIO_ABI);
|
|
26
25
|
/**
|
|
27
26
|
* Mantle layer 1 gas fee flow.
|
|
28
27
|
*
|
|
@@ -41,24 +40,10 @@ class MantleLayer1GasFeeFlow extends OracleLayer1GasFeeFlow_1.OracleLayer1GasFee
|
|
|
41
40
|
transactionMeta.txParams.gasLimit);
|
|
42
41
|
}
|
|
43
42
|
async transformOracleFee(oracleFee, request) {
|
|
44
|
-
const {
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
// Direct `eth_call` RPC request rather than an ethers `Contract` with
|
|
49
|
-
// `Web3Provider`, whose `setTimeout`-based dispatch never fires on React
|
|
50
|
-
// Native when the timer pump is starved (e.g. iOS display link freeze).
|
|
51
|
-
// See https://github.com/MetaMask/metamask-mobile/issues/32863
|
|
52
|
-
const result = await (0, provider_1.rpcRequest)({
|
|
53
|
-
messenger,
|
|
54
|
-
networkClientId,
|
|
55
|
-
method: 'eth_call',
|
|
56
|
-
params: [{ to, data }, 'latest'],
|
|
57
|
-
});
|
|
58
|
-
if (typeof result !== 'string' || result === '0x') {
|
|
59
|
-
throw new Error('No value returned from token ratio contract');
|
|
60
|
-
}
|
|
61
|
-
const tokenRatio = (0, utils_1.toBN)(result);
|
|
43
|
+
const { provider, transactionMeta } = request;
|
|
44
|
+
const oracleAddress = this.getOracleAddressForChain(transactionMeta.chainId);
|
|
45
|
+
const contract = new contracts_1.Contract(oracleAddress, TOKEN_RATIO_ABI, new providers_1.Web3Provider(provider));
|
|
46
|
+
const tokenRatio = (0, utils_1.toBN)(await contract.tokenRatio());
|
|
62
47
|
return oracleFee.mul(tokenRatio);
|
|
63
48
|
}
|
|
64
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MantleLayer1GasFeeFlow.cjs","sourceRoot":"","sources":["../../src/gas-flows/MantleLayer1GasFeeFlow.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"MantleLayer1GasFeeFlow.cjs","sourceRoot":"","sources":["../../src/gas-flows/MantleLayer1GasFeeFlow.ts"],"names":[],"mappings":";;;AAAA,wDAAoD;AACpD,wDAAwD;AAKxD,gDAAyC;AAGzC,8CAAsC;AACtC,yEAAkE;AAElE,MAAM,gBAAgB,GAAU,CAAC,qBAAS,CAAC,MAAM,EAAE,qBAAS,CAAC,cAAc,CAAC,CAAC;AAE7E,MAAM,eAAe,GAAG;IACtB;QACE,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE;YACP;gBACE,YAAY,EAAE,SAAS;gBACvB,IAAI,EAAE,EAAE;gBACR,IAAI,EAAE,SAAS;aAChB;SACF;QACD,eAAe,EAAE,MAAM;QACvB,IAAI,EAAE,UAAU;KACjB;CACF,CAAC;AAEF;;;;;;;GAOG;AACH,MAAa,sBAAuB,SAAQ,+CAAsB;IAChE,KAAK,CAAC,kBAAkB,CAAC,EACvB,eAAe,GAIhB;QACC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IAC5D,CAAC;IAEkB,iBAAiB,CAClC,eAAgC;QAEhC,OAAO,CACL,eAAe,CAAC,OAAO;YACvB,eAAe,CAAC,QAAQ,CAAC,GAAG;YAC5B,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAClC,CAAC;IACJ,CAAC;IAEkB,KAAK,CAAC,kBAAkB,CACzC,SAAa,EACb,OAAgC;QAEhC,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;QAC9C,MAAM,aAAa,GAAG,IAAI,CAAC,wBAAwB,CACjD,eAAe,CAAC,OAAO,CACxB,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,oBAAQ,CAC3B,aAAa,EACb,eAAe,EACf,IAAI,wBAAY,CAAC,QAAuC,CAAC,CAC1D,CAAC;QAEF,MAAM,UAAU,GAAG,IAAA,YAAI,EAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACrD,OAAO,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;CACF;AAtCD,wDAsCC","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport type { ExternalProvider } from '@ethersproject/providers';\nimport type { Hex } from '@metamask/utils';\nimport type BN from 'bn.js';\n\nimport { CHAIN_IDS } from '../constants';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type { Layer1GasFeeFlowRequest, TransactionMeta } from '../types';\nimport { toBN } from '../utils/utils';\nimport { OracleLayer1GasFeeFlow } from './OracleLayer1GasFeeFlow';\n\nconst MANTLE_CHAIN_IDS: Hex[] = [CHAIN_IDS.MANTLE, CHAIN_IDS.MANTLE_SEPOLIA];\n\nconst TOKEN_RATIO_ABI = [\n {\n inputs: [],\n name: 'tokenRatio',\n outputs: [\n {\n internalType: 'uint256',\n name: '',\n type: 'uint256',\n },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n];\n\n/**\n * Mantle layer 1 gas fee flow.\n *\n * Mantle uses MNT as its native gas token, but the oracle's getL1Fee returns\n * values denominated in ETH. This subclass multiplies the L1 fee by the\n * tokenRatio (ETH/MNT exchange rate) from the oracle contract to convert\n * the fee to MNT.\n */\nexport class MantleLayer1GasFeeFlow extends OracleLayer1GasFeeFlow {\n async matchesTransaction({\n transactionMeta,\n }: {\n transactionMeta: TransactionMeta;\n messenger: TransactionControllerMessenger;\n }): Promise<boolean> {\n return MANTLE_CHAIN_IDS.includes(transactionMeta.chainId);\n }\n\n protected override getOperatorFeeGas(\n transactionMeta: TransactionMeta,\n ): string | undefined {\n return (\n transactionMeta.gasUsed ??\n transactionMeta.txParams.gas ??\n transactionMeta.txParams.gasLimit\n );\n }\n\n protected override async transformOracleFee(\n oracleFee: BN,\n request: Layer1GasFeeFlowRequest,\n ): Promise<BN> {\n const { provider, transactionMeta } = request;\n const oracleAddress = this.getOracleAddressForChain(\n transactionMeta.chainId,\n );\n\n const contract = new Contract(\n oracleAddress,\n TOKEN_RATIO_ABI,\n new Web3Provider(provider as unknown as ExternalProvider),\n );\n\n const tokenRatio = toBN(await contract.tokenRatio());\n return oracleFee.mul(tokenRatio);\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MantleLayer1GasFeeFlow.d.cts","sourceRoot":"","sources":["../../src/gas-flows/MantleLayer1GasFeeFlow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MantleLayer1GasFeeFlow.d.cts","sourceRoot":"","sources":["../../src/gas-flows/MantleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc;AAG5B,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EAAE,uBAAuB,EAAE,eAAe,EAAE,qBAAiB;AAEzE,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAoBlE;;;;;;;GAOG;AACH,qBAAa,sBAAuB,SAAQ,sBAAsB;IAC1D,kBAAkB,CAAC,EACvB,eAAe,GAChB,EAAE;QACD,eAAe,EAAE,eAAe,CAAC;QACjC,SAAS,EAAE,8BAA8B,CAAC;KAC3C,GAAG,OAAO,CAAC,OAAO,CAAC;cAID,iBAAiB,CAClC,eAAe,EAAE,eAAe,GAC/B,MAAM,GAAG,SAAS;cAQI,kBAAkB,CACzC,SAAS,EAAE,EAAE,EACb,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,EAAE,CAAC;CAef"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MantleLayer1GasFeeFlow.d.mts","sourceRoot":"","sources":["../../src/gas-flows/MantleLayer1GasFeeFlow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MantleLayer1GasFeeFlow.d.mts","sourceRoot":"","sources":["../../src/gas-flows/MantleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc;AAG5B,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EAAE,uBAAuB,EAAE,eAAe,EAAE,qBAAiB;AAEzE,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAoBlE;;;;;;;GAOG;AACH,qBAAa,sBAAuB,SAAQ,sBAAsB;IAC1D,kBAAkB,CAAC,EACvB,eAAe,GAChB,EAAE;QACD,eAAe,EAAE,eAAe,CAAC;QACjC,SAAS,EAAE,8BAA8B,CAAC;KAC3C,GAAG,OAAO,CAAC,OAAO,CAAC;cAID,iBAAiB,CAClC,eAAe,EAAE,eAAe,GAC/B,MAAM,GAAG,SAAS;cAQI,kBAAkB,CACzC,SAAS,EAAE,EAAE,EACb,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,EAAE,CAAC;CAef"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Contract } from "@ethersproject/contracts";
|
|
2
|
+
import { Web3Provider } from "@ethersproject/providers";
|
|
2
3
|
import { CHAIN_IDS } from "../constants.mjs";
|
|
3
|
-
import { rpcRequest } from "../utils/provider.mjs";
|
|
4
4
|
import { toBN } from "../utils/utils.mjs";
|
|
5
5
|
import { OracleLayer1GasFeeFlow } from "./OracleLayer1GasFeeFlow.mjs";
|
|
6
6
|
const MANTLE_CHAIN_IDS = [CHAIN_IDS.MANTLE, CHAIN_IDS.MANTLE_SEPOLIA];
|
|
@@ -19,7 +19,6 @@ const TOKEN_RATIO_ABI = [
|
|
|
19
19
|
type: 'function',
|
|
20
20
|
},
|
|
21
21
|
];
|
|
22
|
-
const TOKEN_RATIO_INTERFACE = new Interface(TOKEN_RATIO_ABI);
|
|
23
22
|
/**
|
|
24
23
|
* Mantle layer 1 gas fee flow.
|
|
25
24
|
*
|
|
@@ -38,24 +37,10 @@ export class MantleLayer1GasFeeFlow extends OracleLayer1GasFeeFlow {
|
|
|
38
37
|
transactionMeta.txParams.gasLimit);
|
|
39
38
|
}
|
|
40
39
|
async transformOracleFee(oracleFee, request) {
|
|
41
|
-
const {
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
// Direct `eth_call` RPC request rather than an ethers `Contract` with
|
|
46
|
-
// `Web3Provider`, whose `setTimeout`-based dispatch never fires on React
|
|
47
|
-
// Native when the timer pump is starved (e.g. iOS display link freeze).
|
|
48
|
-
// See https://github.com/MetaMask/metamask-mobile/issues/32863
|
|
49
|
-
const result = await rpcRequest({
|
|
50
|
-
messenger,
|
|
51
|
-
networkClientId,
|
|
52
|
-
method: 'eth_call',
|
|
53
|
-
params: [{ to, data }, 'latest'],
|
|
54
|
-
});
|
|
55
|
-
if (typeof result !== 'string' || result === '0x') {
|
|
56
|
-
throw new Error('No value returned from token ratio contract');
|
|
57
|
-
}
|
|
58
|
-
const tokenRatio = toBN(result);
|
|
40
|
+
const { provider, transactionMeta } = request;
|
|
41
|
+
const oracleAddress = this.getOracleAddressForChain(transactionMeta.chainId);
|
|
42
|
+
const contract = new Contract(oracleAddress, TOKEN_RATIO_ABI, new Web3Provider(provider));
|
|
43
|
+
const tokenRatio = toBN(await contract.tokenRatio());
|
|
59
44
|
return oracleFee.mul(tokenRatio);
|
|
60
45
|
}
|
|
61
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MantleLayer1GasFeeFlow.mjs","sourceRoot":"","sources":["../../src/gas-flows/MantleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"MantleLayer1GasFeeFlow.mjs","sourceRoot":"","sources":["../../src/gas-flows/MantleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iCAAiC;AACpD,OAAO,EAAE,YAAY,EAAE,iCAAiC;AAKxD,OAAO,EAAE,SAAS,EAAE,yBAAqB;AAGzC,OAAO,EAAE,IAAI,EAAE,2BAAuB;AACtC,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAElE,MAAM,gBAAgB,GAAU,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;AAE7E,MAAM,eAAe,GAAG;IACtB;QACE,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE;YACP;gBACE,YAAY,EAAE,SAAS;gBACvB,IAAI,EAAE,EAAE;gBACR,IAAI,EAAE,SAAS;aAChB;SACF;QACD,eAAe,EAAE,MAAM;QACvB,IAAI,EAAE,UAAU;KACjB;CACF,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,OAAO,sBAAuB,SAAQ,sBAAsB;IAChE,KAAK,CAAC,kBAAkB,CAAC,EACvB,eAAe,GAIhB;QACC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IAC5D,CAAC;IAEkB,iBAAiB,CAClC,eAAgC;QAEhC,OAAO,CACL,eAAe,CAAC,OAAO;YACvB,eAAe,CAAC,QAAQ,CAAC,GAAG;YAC5B,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAClC,CAAC;IACJ,CAAC;IAEkB,KAAK,CAAC,kBAAkB,CACzC,SAAa,EACb,OAAgC;QAEhC,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;QAC9C,MAAM,aAAa,GAAG,IAAI,CAAC,wBAAwB,CACjD,eAAe,CAAC,OAAO,CACxB,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAC3B,aAAa,EACb,eAAe,EACf,IAAI,YAAY,CAAC,QAAuC,CAAC,CAC1D,CAAC;QAEF,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACrD,OAAO,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;CACF","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport type { ExternalProvider } from '@ethersproject/providers';\nimport type { Hex } from '@metamask/utils';\nimport type BN from 'bn.js';\n\nimport { CHAIN_IDS } from '../constants';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type { Layer1GasFeeFlowRequest, TransactionMeta } from '../types';\nimport { toBN } from '../utils/utils';\nimport { OracleLayer1GasFeeFlow } from './OracleLayer1GasFeeFlow';\n\nconst MANTLE_CHAIN_IDS: Hex[] = [CHAIN_IDS.MANTLE, CHAIN_IDS.MANTLE_SEPOLIA];\n\nconst TOKEN_RATIO_ABI = [\n {\n inputs: [],\n name: 'tokenRatio',\n outputs: [\n {\n internalType: 'uint256',\n name: '',\n type: 'uint256',\n },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n];\n\n/**\n * Mantle layer 1 gas fee flow.\n *\n * Mantle uses MNT as its native gas token, but the oracle's getL1Fee returns\n * values denominated in ETH. This subclass multiplies the L1 fee by the\n * tokenRatio (ETH/MNT exchange rate) from the oracle contract to convert\n * the fee to MNT.\n */\nexport class MantleLayer1GasFeeFlow extends OracleLayer1GasFeeFlow {\n async matchesTransaction({\n transactionMeta,\n }: {\n transactionMeta: TransactionMeta;\n messenger: TransactionControllerMessenger;\n }): Promise<boolean> {\n return MANTLE_CHAIN_IDS.includes(transactionMeta.chainId);\n }\n\n protected override getOperatorFeeGas(\n transactionMeta: TransactionMeta,\n ): string | undefined {\n return (\n transactionMeta.gasUsed ??\n transactionMeta.txParams.gas ??\n transactionMeta.txParams.gasLimit\n );\n }\n\n protected override async transformOracleFee(\n oracleFee: BN,\n request: Layer1GasFeeFlowRequest,\n ): Promise<BN> {\n const { provider, transactionMeta } = request;\n const oracleAddress = this.getOracleAddressForChain(\n transactionMeta.chainId,\n );\n\n const contract = new Contract(\n oracleAddress,\n TOKEN_RATIO_ABI,\n new Web3Provider(provider as unknown as ExternalProvider),\n );\n\n const tokenRatio = toBN(await contract.tokenRatio());\n return oracleFee.mul(tokenRatio);\n }\n}\n"]}
|
|
@@ -7,15 +7,15 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
7
7
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
8
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
9
|
};
|
|
10
|
-
var _OracleLayer1GasFeeFlow_instances, _OracleLayer1GasFeeFlow_getOracleLayer1GasFee, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee, _OracleLayer1GasFeeFlow_buildUnserializedTransaction, _OracleLayer1GasFeeFlow_buildTransactionParams,
|
|
10
|
+
var _OracleLayer1GasFeeFlow_instances, _OracleLayer1GasFeeFlow_getOracleLayer1GasFee, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee, _OracleLayer1GasFeeFlow_buildUnserializedTransaction, _OracleLayer1GasFeeFlow_buildTransactionParams, _OracleLayer1GasFeeFlow_getGasPriceOracleContract;
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.OracleLayer1GasFeeFlow = void 0;
|
|
13
|
-
const
|
|
13
|
+
const contracts_1 = require("@ethersproject/contracts");
|
|
14
|
+
const providers_1 = require("@ethersproject/providers");
|
|
14
15
|
const utils_1 = require("@metamask/utils");
|
|
15
16
|
const bn_js_1 = __importDefault(require("bn.js"));
|
|
16
17
|
const logger_1 = require("../logger.cjs");
|
|
17
18
|
const prepare_1 = require("../utils/prepare.cjs");
|
|
18
|
-
const provider_1 = require("../utils/provider.cjs");
|
|
19
19
|
const utils_2 = require("../utils/utils.cjs");
|
|
20
20
|
const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'oracle-layer1-gas-fee-flow');
|
|
21
21
|
const ZERO = new bn_js_1.default(0);
|
|
@@ -63,7 +63,6 @@ const GAS_PRICE_ORACLE_ABI = [
|
|
|
63
63
|
];
|
|
64
64
|
// Default OP Stack gas price oracle address used across supported networks
|
|
65
65
|
const DEFAULT_GAS_PRICE_ORACLE_ADDRESS = '0x420000000000000000000000000000000000000F';
|
|
66
|
-
const GAS_PRICE_ORACLE_INTERFACE = new abi_1.Interface(GAS_PRICE_ORACLE_ABI);
|
|
67
66
|
/**
|
|
68
67
|
* Layer 1 gas fee flow that obtains gas fee estimate using an oracle smart contract.
|
|
69
68
|
*/
|
|
@@ -102,7 +101,7 @@ class OracleLayer1GasFeeFlow {
|
|
|
102
101
|
* Defaults to returning the fee unchanged.
|
|
103
102
|
*
|
|
104
103
|
* @param oracleFee - The raw L1 fee returned by the oracle contract.
|
|
105
|
-
* @param _request - The original fee flow request (
|
|
104
|
+
* @param _request - The original fee flow request (provider + transaction).
|
|
106
105
|
* @returns The transformed fee.
|
|
107
106
|
*/
|
|
108
107
|
async transformOracleFee(oracleFee, _request) {
|
|
@@ -110,9 +109,11 @@ class OracleLayer1GasFeeFlow {
|
|
|
110
109
|
}
|
|
111
110
|
async getLayer1Fee(request) {
|
|
112
111
|
try {
|
|
113
|
-
const
|
|
112
|
+
const { provider, transactionMeta } = request;
|
|
113
|
+
const contract = __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getGasPriceOracleContract).call(this, provider, transactionMeta.chainId);
|
|
114
|
+
const oracleFee = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getOracleLayer1GasFee).call(this, contract, transactionMeta);
|
|
114
115
|
const transformedFee = await this.transformOracleFee(oracleFee, request);
|
|
115
|
-
const operatorFee = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee).call(this,
|
|
116
|
+
const operatorFee = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee).call(this, contract, transactionMeta);
|
|
116
117
|
return {
|
|
117
118
|
layer1Fee: (0, utils_1.add0x)((0, utils_2.padHexToEvenLength)(transformedFee.add(operatorFee).toString(16))),
|
|
118
119
|
};
|
|
@@ -136,25 +137,21 @@ class OracleLayer1GasFeeFlow {
|
|
|
136
137
|
}
|
|
137
138
|
}
|
|
138
139
|
exports.OracleLayer1GasFeeFlow = OracleLayer1GasFeeFlow;
|
|
139
|
-
_OracleLayer1GasFeeFlow_instances = new WeakSet(), _OracleLayer1GasFeeFlow_getOracleLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOracleLayer1GasFee(
|
|
140
|
-
const serializedTransaction = __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_buildUnserializedTransaction).call(this,
|
|
141
|
-
const result = await
|
|
142
|
-
|
|
143
|
-
]);
|
|
144
|
-
if (typeof result !== 'string' || result === '0x') {
|
|
140
|
+
_OracleLayer1GasFeeFlow_instances = new WeakSet(), _OracleLayer1GasFeeFlow_getOracleLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOracleLayer1GasFee(contract, transactionMeta) {
|
|
141
|
+
const serializedTransaction = __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_buildUnserializedTransaction).call(this, transactionMeta, this.shouldSignTransaction()).serialize();
|
|
142
|
+
const result = await contract.getL1Fee(serializedTransaction);
|
|
143
|
+
if (result === undefined) {
|
|
145
144
|
throw new Error('No value returned from oracle contract');
|
|
146
145
|
}
|
|
147
146
|
return (0, utils_2.toBN)(result);
|
|
148
|
-
}, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee(
|
|
149
|
-
const gas = this.getOperatorFeeGas(
|
|
147
|
+
}, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee(contract, transactionMeta) {
|
|
148
|
+
const gas = this.getOperatorFeeGas(transactionMeta);
|
|
150
149
|
if (!gas) {
|
|
151
150
|
return ZERO;
|
|
152
151
|
}
|
|
153
152
|
try {
|
|
154
|
-
const result = await
|
|
155
|
-
|
|
156
|
-
]);
|
|
157
|
-
if (typeof result !== 'string' || result === '0x') {
|
|
153
|
+
const result = await contract.getOperatorFee(gas);
|
|
154
|
+
if (result === undefined) {
|
|
158
155
|
return ZERO;
|
|
159
156
|
}
|
|
160
157
|
return (0, utils_2.toBN)(result);
|
|
@@ -179,23 +176,9 @@ _OracleLayer1GasFeeFlow_instances = new WeakSet(), _OracleLayer1GasFeeFlow_getOr
|
|
|
179
176
|
...transactionMeta.txParams,
|
|
180
177
|
gasLimit: transactionMeta.txParams.gas,
|
|
181
178
|
};
|
|
182
|
-
},
|
|
183
|
-
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
// when the timer pump is starved (e.g. iOS display link freeze), blocking
|
|
187
|
-
// `addTransaction` indefinitely.
|
|
188
|
-
// See https://github.com/MetaMask/metamask-mobile/issues/32863
|
|
189
|
-
async function _OracleLayer1GasFeeFlow_callGasPriceOracle(request, functionName, args) {
|
|
190
|
-
const { messenger, transactionMeta } = request;
|
|
191
|
-
const { chainId, networkClientId } = transactionMeta;
|
|
192
|
-
const to = this.getOracleAddressForChain(chainId);
|
|
193
|
-
const data = GAS_PRICE_ORACLE_INTERFACE.encodeFunctionData(functionName, args);
|
|
194
|
-
return await (0, provider_1.rpcRequest)({
|
|
195
|
-
messenger,
|
|
196
|
-
networkClientId,
|
|
197
|
-
method: 'eth_call',
|
|
198
|
-
params: [{ to, data }, 'latest'],
|
|
199
|
-
});
|
|
179
|
+
}, _OracleLayer1GasFeeFlow_getGasPriceOracleContract = function _OracleLayer1GasFeeFlow_getGasPriceOracleContract(provider, chainId) {
|
|
180
|
+
return new contracts_1.Contract(this.getOracleAddressForChain(chainId), GAS_PRICE_ORACLE_ABI,
|
|
181
|
+
// Network controller provider type is incompatible with ethers provider
|
|
182
|
+
new providers_1.Web3Provider(provider));
|
|
200
183
|
};
|
|
201
184
|
//# sourceMappingURL=OracleLayer1GasFeeFlow.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OracleLayer1GasFeeFlow.cjs","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport type { Hex } from '@metamask/utils';\nimport { add0x, createModuleLogger } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type {\n Layer1GasFeeFlow,\n Layer1GasFeeFlowRequest,\n Layer1GasFeeFlowResponse,\n TransactionMeta,\n} from '../types';\nimport { prepareTransaction } from '../utils/prepare';\nimport { rpcRequest } from '../utils/provider';\nimport { padHexToEvenLength, toBN } from '../utils/utils';\n\nconst log = createModuleLogger(projectLogger, 'oracle-layer1-gas-fee-flow');\n\nconst ZERO = new BN(0);\n\nconst DUMMY_KEY =\n 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789';\n\nconst GAS_PRICE_ORACLE_ABI = [\n {\n inputs: [\n {\n internalType: 'bytes',\n name: '_data',\n type: 'bytes',\n },\n ],\n name: 'getL1Fee',\n outputs: [\n {\n internalType: 'uint256',\n name: '',\n type: 'uint256',\n },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n // only available post Isthmus\n {\n inputs: [\n {\n internalType: 'uint256',\n name: '_gasUsed',\n type: 'uint256',\n },\n ],\n name: 'getOperatorFee',\n outputs: [\n {\n internalType: 'uint256',\n name: '',\n type: 'uint256',\n },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n];\n\n// Default OP Stack gas price oracle address used across supported networks\nconst DEFAULT_GAS_PRICE_ORACLE_ADDRESS =\n '0x420000000000000000000000000000000000000F' as Hex;\n\nconst GAS_PRICE_ORACLE_INTERFACE = new Interface(GAS_PRICE_ORACLE_ABI);\n\n/**\n * Layer 1 gas fee flow that obtains gas fee estimate using an oracle smart contract.\n */\nexport abstract class OracleLayer1GasFeeFlow implements Layer1GasFeeFlow {\n /**\n * Resolves the oracle address for the given chain. Subclasses can override\n * this method to provide chain-specific oracle addresses. By default, this\n * returns the standard OP Stack gas price oracle address.\n *\n * @param _chainId - The chain ID to resolve the oracle address for.\n * @returns The oracle address for the given chain.\n */\n protected getOracleAddressForChain(_chainId: Hex): Hex {\n return DEFAULT_GAS_PRICE_ORACLE_ADDRESS;\n }\n\n /**\n * Whether to sign the transaction with a dummy key prior to calling the\n * oracle contract. Some oracle contracts require a signed payload even for\n * read-only methods.\n *\n * Subclasses can override to enable signing when needed. Defaults to false.\n *\n * @returns Whether the transaction should be signed prior to the oracle call.\n */\n protected shouldSignTransaction(): boolean {\n return false;\n }\n\n abstract matchesTransaction({\n transactionMeta,\n messenger,\n }: {\n transactionMeta: TransactionMeta;\n messenger: TransactionControllerMessenger;\n }): Promise<boolean>;\n\n /**\n * Transforms the raw oracle L1 fee before it is combined with the operator\n * fee. Subclasses can override this to apply chain-specific conversions\n * (e.g. currency conversion via an on-chain exchange rate).\n *\n * Defaults to returning the fee unchanged.\n *\n * @param oracleFee - The raw L1 fee returned by the oracle contract.\n * @param _request - The original fee flow request (messenger + transaction).\n * @returns The transformed fee.\n */\n protected async transformOracleFee(\n oracleFee: BN,\n _request: Layer1GasFeeFlowRequest,\n ): Promise<BN> {\n return oracleFee;\n }\n\n async getLayer1Fee(\n request: Layer1GasFeeFlowRequest,\n ): Promise<Layer1GasFeeFlowResponse> {\n try {\n const oracleFee = await this.#getOracleLayer1GasFee(request);\n const transformedFee = await this.transformOracleFee(oracleFee, request);\n const operatorFee = await this.#getOperatorLayer1GasFee(request);\n\n return {\n layer1Fee: add0x(\n padHexToEvenLength(transformedFee.add(operatorFee).toString(16)),\n ),\n };\n } catch (error) {\n log('Failed to get oracle layer 1 gas fee', error);\n throw new Error(`Failed to get oracle layer 1 gas fee`);\n }\n }\n\n async #getOracleLayer1GasFee(request: Layer1GasFeeFlowRequest): Promise<BN> {\n const serializedTransaction = this.#buildUnserializedTransaction(\n request.transactionMeta,\n this.shouldSignTransaction(),\n ).serialize();\n\n const result = await this.#callGasPriceOracle(request, 'getL1Fee', [\n serializedTransaction,\n ]);\n\n if (typeof result !== 'string' || result === '0x') {\n throw new Error('No value returned from oracle contract');\n }\n\n return toBN(result);\n }\n\n /**\n * Returns the gas value to pass to the operator-fee oracle, or undefined\n * to skip the operator-fee call entirely. Defaults to the simulated\n * `gasUsed` on the transaction. Subclasses can override to supply a\n * fallback (e.g. estimated gas limit) when `gasUsed` is unavailable.\n *\n * @param transactionMeta - The transaction metadata.\n * @returns The gas value, or undefined to skip the operator-fee call.\n */\n protected getOperatorFeeGas(\n transactionMeta: TransactionMeta,\n ): string | undefined {\n return transactionMeta.gasUsed;\n }\n\n async #getOperatorLayer1GasFee(\n request: Layer1GasFeeFlowRequest,\n ): Promise<BN> {\n const gas = this.getOperatorFeeGas(request.transactionMeta);\n\n if (!gas) {\n return ZERO;\n }\n\n try {\n const result = await this.#callGasPriceOracle(request, 'getOperatorFee', [\n gas,\n ]);\n\n if (typeof result !== 'string' || result === '0x') {\n return ZERO;\n }\n\n return toBN(result);\n } catch (error) {\n log('Failed to get operator layer 1 gas fee', error);\n return ZERO;\n }\n }\n\n #buildUnserializedTransaction(\n transactionMeta: TransactionMeta,\n sign: boolean,\n ): ReturnType<typeof prepareTransaction> {\n const txParams = this.#buildTransactionParams(transactionMeta);\n const { chainId } = transactionMeta;\n\n let unserializedTransaction = prepareTransaction(chainId, txParams);\n\n if (sign) {\n // eslint-disable-next-line no-restricted-globals\n const keyBuffer = Buffer.from(DUMMY_KEY, 'hex');\n const keyBytes = Uint8Array.from(keyBuffer);\n unserializedTransaction = unserializedTransaction.sign(keyBytes);\n }\n\n return unserializedTransaction;\n }\n\n #buildTransactionParams(\n transactionMeta: TransactionMeta,\n ): TransactionMeta['txParams'] {\n return {\n ...transactionMeta.txParams,\n gasLimit: transactionMeta.txParams.gas,\n };\n }\n\n // The oracle is called via a direct `eth_call` RPC request rather than an\n // ethers `Contract` with `Web3Provider`, as `Web3Provider` schedules its\n // JSON-RPC dispatch with `setTimeout`, which never fires on React Native\n // when the timer pump is starved (e.g. iOS display link freeze), blocking\n // `addTransaction` indefinitely.\n // See https://github.com/MetaMask/metamask-mobile/issues/32863\n async #callGasPriceOracle(\n request: Layer1GasFeeFlowRequest,\n functionName: string,\n args: readonly unknown[],\n ): Promise<unknown> {\n const { messenger, transactionMeta } = request;\n const { chainId, networkClientId } = transactionMeta;\n\n const to = this.getOracleAddressForChain(chainId);\n const data = GAS_PRICE_ORACLE_INTERFACE.encodeFunctionData(\n functionName,\n args,\n ) as Hex;\n\n return await rpcRequest({\n messenger,\n networkClientId,\n method: 'eth_call',\n params: [{ to, data }, 'latest'],\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"OracleLayer1GasFeeFlow.cjs","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"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","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport type { ExternalProvider } from '@ethersproject/providers';\nimport type { Hex } from '@metamask/utils';\nimport { add0x, createModuleLogger } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type {\n Layer1GasFeeFlow,\n Layer1GasFeeFlowRequest,\n Layer1GasFeeFlowResponse,\n TransactionMeta,\n} from '../types';\nimport { prepareTransaction } from '../utils/prepare';\nimport { padHexToEvenLength, toBN } from '../utils/utils';\n\nconst log = createModuleLogger(projectLogger, 'oracle-layer1-gas-fee-flow');\n\nconst ZERO = new BN(0);\n\nconst DUMMY_KEY =\n 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789';\n\nconst GAS_PRICE_ORACLE_ABI = [\n {\n inputs: [\n {\n internalType: 'bytes',\n name: '_data',\n type: 'bytes',\n },\n ],\n name: 'getL1Fee',\n outputs: [\n {\n internalType: 'uint256',\n name: '',\n type: 'uint256',\n },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n // only available post Isthmus\n {\n inputs: [\n {\n internalType: 'uint256',\n name: '_gasUsed',\n type: 'uint256',\n },\n ],\n name: 'getOperatorFee',\n outputs: [\n {\n internalType: 'uint256',\n name: '',\n type: 'uint256',\n },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n];\n\n// Default OP Stack gas price oracle address used across supported networks\nconst DEFAULT_GAS_PRICE_ORACLE_ADDRESS =\n '0x420000000000000000000000000000000000000F' as Hex;\n\n/**\n * Layer 1 gas fee flow that obtains gas fee estimate using an oracle smart contract.\n */\nexport abstract class OracleLayer1GasFeeFlow implements Layer1GasFeeFlow {\n /**\n * Resolves the oracle address for the given chain. Subclasses can override\n * this method to provide chain-specific oracle addresses. By default, this\n * returns the standard OP Stack gas price oracle address.\n *\n * @param _chainId - The chain ID to resolve the oracle address for.\n * @returns The oracle address for the given chain.\n */\n protected getOracleAddressForChain(_chainId: Hex): Hex {\n return DEFAULT_GAS_PRICE_ORACLE_ADDRESS;\n }\n\n /**\n * Whether to sign the transaction with a dummy key prior to calling the\n * oracle contract. Some oracle contracts require a signed payload even for\n * read-only methods.\n *\n * Subclasses can override to enable signing when needed. Defaults to false.\n *\n * @returns Whether the transaction should be signed prior to the oracle call.\n */\n protected shouldSignTransaction(): boolean {\n return false;\n }\n\n abstract matchesTransaction({\n transactionMeta,\n messenger,\n }: {\n transactionMeta: TransactionMeta;\n messenger: TransactionControllerMessenger;\n }): Promise<boolean>;\n\n /**\n * Transforms the raw oracle L1 fee before it is combined with the operator\n * fee. Subclasses can override this to apply chain-specific conversions\n * (e.g. currency conversion via an on-chain exchange rate).\n *\n * Defaults to returning the fee unchanged.\n *\n * @param oracleFee - The raw L1 fee returned by the oracle contract.\n * @param _request - The original fee flow request (provider + transaction).\n * @returns The transformed fee.\n */\n protected async transformOracleFee(\n oracleFee: BN,\n _request: Layer1GasFeeFlowRequest,\n ): Promise<BN> {\n return oracleFee;\n }\n\n async getLayer1Fee(\n request: Layer1GasFeeFlowRequest,\n ): Promise<Layer1GasFeeFlowResponse> {\n try {\n const { provider, transactionMeta } = request;\n\n const contract = this.#getGasPriceOracleContract(\n provider,\n transactionMeta.chainId,\n );\n\n const oracleFee = await this.#getOracleLayer1GasFee(\n contract,\n transactionMeta,\n );\n const transformedFee = await this.transformOracleFee(oracleFee, request);\n const operatorFee = await this.#getOperatorLayer1GasFee(\n contract,\n transactionMeta,\n );\n\n return {\n layer1Fee: add0x(\n padHexToEvenLength(transformedFee.add(operatorFee).toString(16)),\n ),\n };\n } catch (error) {\n log('Failed to get oracle layer 1 gas fee', error);\n throw new Error(`Failed to get oracle layer 1 gas fee`);\n }\n }\n\n async #getOracleLayer1GasFee(\n contract: Contract,\n transactionMeta: TransactionMeta,\n ): Promise<BN> {\n const serializedTransaction = this.#buildUnserializedTransaction(\n transactionMeta,\n this.shouldSignTransaction(),\n ).serialize();\n\n const result = await contract.getL1Fee(serializedTransaction);\n\n if (result === undefined) {\n throw new Error('No value returned from oracle contract');\n }\n\n return toBN(result);\n }\n\n /**\n * Returns the gas value to pass to the operator-fee oracle, or undefined\n * to skip the operator-fee call entirely. Defaults to the simulated\n * `gasUsed` on the transaction. Subclasses can override to supply a\n * fallback (e.g. estimated gas limit) when `gasUsed` is unavailable.\n *\n * @param transactionMeta - The transaction metadata.\n * @returns The gas value, or undefined to skip the operator-fee call.\n */\n protected getOperatorFeeGas(\n transactionMeta: TransactionMeta,\n ): string | undefined {\n return transactionMeta.gasUsed;\n }\n\n async #getOperatorLayer1GasFee(\n contract: Contract,\n transactionMeta: TransactionMeta,\n ): Promise<BN> {\n const gas = this.getOperatorFeeGas(transactionMeta);\n\n if (!gas) {\n return ZERO;\n }\n\n try {\n const result = await contract.getOperatorFee(gas);\n\n if (result === undefined) {\n return ZERO;\n }\n\n return toBN(result);\n } catch (error) {\n log('Failed to get operator layer 1 gas fee', error);\n return ZERO;\n }\n }\n\n #buildUnserializedTransaction(\n transactionMeta: TransactionMeta,\n sign: boolean,\n ): ReturnType<typeof prepareTransaction> {\n const txParams = this.#buildTransactionParams(transactionMeta);\n const { chainId } = transactionMeta;\n\n let unserializedTransaction = prepareTransaction(chainId, txParams);\n\n if (sign) {\n // eslint-disable-next-line no-restricted-globals\n const keyBuffer = Buffer.from(DUMMY_KEY, 'hex');\n const keyBytes = Uint8Array.from(keyBuffer);\n unserializedTransaction = unserializedTransaction.sign(keyBytes);\n }\n\n return unserializedTransaction;\n }\n\n #buildTransactionParams(\n transactionMeta: TransactionMeta,\n ): TransactionMeta['txParams'] {\n return {\n ...transactionMeta.txParams,\n gasLimit: transactionMeta.txParams.gas,\n };\n }\n\n #getGasPriceOracleContract(\n provider: Layer1GasFeeFlowRequest['provider'],\n chainId: Hex,\n ): Contract {\n return new Contract(\n this.getOracleAddressForChain(chainId),\n GAS_PRICE_ORACLE_ABI,\n // Network controller provider type is incompatible with ethers provider\n new Web3Provider(provider as unknown as ExternalProvider),\n );\n }\n}\n"]}
|
|
@@ -38,7 +38,7 @@ export declare abstract class OracleLayer1GasFeeFlow implements Layer1GasFeeFlow
|
|
|
38
38
|
* Defaults to returning the fee unchanged.
|
|
39
39
|
*
|
|
40
40
|
* @param oracleFee - The raw L1 fee returned by the oracle contract.
|
|
41
|
-
* @param _request - The original fee flow request (
|
|
41
|
+
* @param _request - The original fee flow request (provider + transaction).
|
|
42
42
|
* @returns The transformed fee.
|
|
43
43
|
*/
|
|
44
44
|
protected transformOracleFee(oracleFee: BN, _request: Layer1GasFeeFlowRequest): Promise<BN>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OracleLayer1GasFeeFlow.d.cts","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OracleLayer1GasFeeFlow.d.cts","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,OAAO,EAAE,cAAc;AAGvB,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EACvB,wBAAwB,EACxB,eAAe,EAChB,qBAAiB;AAyDlB;;GAEG;AACH,8BAAsB,sBAAuB,YAAW,gBAAgB;;IACtE;;;;;;;OAOG;IACH,SAAS,CAAC,wBAAwB,CAAC,QAAQ,EAAE,GAAG,GAAG,GAAG;IAItD;;;;;;;;OAQG;IACH,SAAS,CAAC,qBAAqB,IAAI,OAAO;IAI1C,QAAQ,CAAC,kBAAkB,CAAC,EAC1B,eAAe,EACf,SAAS,GACV,EAAE;QACD,eAAe,EAAE,eAAe,CAAC;QACjC,SAAS,EAAE,8BAA8B,CAAC;KAC3C,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpB;;;;;;;;;;OAUG;cACa,kBAAkB,CAChC,SAAS,EAAE,EAAE,EACb,QAAQ,EAAE,uBAAuB,GAChC,OAAO,CAAC,EAAE,CAAC;IAIR,YAAY,CAChB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,wBAAwB,CAAC;IAgDpC;;;;;;;;OAQG;IACH,SAAS,CAAC,iBAAiB,CACzB,eAAe,EAAE,eAAe,GAC/B,MAAM,GAAG,SAAS;CAmEtB"}
|
|
@@ -38,7 +38,7 @@ export declare abstract class OracleLayer1GasFeeFlow implements Layer1GasFeeFlow
|
|
|
38
38
|
* Defaults to returning the fee unchanged.
|
|
39
39
|
*
|
|
40
40
|
* @param oracleFee - The raw L1 fee returned by the oracle contract.
|
|
41
|
-
* @param _request - The original fee flow request (
|
|
41
|
+
* @param _request - The original fee flow request (provider + transaction).
|
|
42
42
|
* @returns The transformed fee.
|
|
43
43
|
*/
|
|
44
44
|
protected transformOracleFee(oracleFee: BN, _request: Layer1GasFeeFlowRequest): Promise<BN>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OracleLayer1GasFeeFlow.d.mts","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OracleLayer1GasFeeFlow.d.mts","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAE3C,OAAO,EAAE,cAAc;AAGvB,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EACV,gBAAgB,EAChB,uBAAuB,EACvB,wBAAwB,EACxB,eAAe,EAChB,qBAAiB;AAyDlB;;GAEG;AACH,8BAAsB,sBAAuB,YAAW,gBAAgB;;IACtE;;;;;;;OAOG;IACH,SAAS,CAAC,wBAAwB,CAAC,QAAQ,EAAE,GAAG,GAAG,GAAG;IAItD;;;;;;;;OAQG;IACH,SAAS,CAAC,qBAAqB,IAAI,OAAO;IAI1C,QAAQ,CAAC,kBAAkB,CAAC,EAC1B,eAAe,EACf,SAAS,GACV,EAAE;QACD,eAAe,EAAE,eAAe,CAAC;QACjC,SAAS,EAAE,8BAA8B,CAAC;KAC3C,GAAG,OAAO,CAAC,OAAO,CAAC;IAEpB;;;;;;;;;;OAUG;cACa,kBAAkB,CAChC,SAAS,EAAE,EAAE,EACb,QAAQ,EAAE,uBAAuB,GAChC,OAAO,CAAC,EAAE,CAAC;IAIR,YAAY,CAChB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,wBAAwB,CAAC;IAgDpC;;;;;;;;OAQG;IACH,SAAS,CAAC,iBAAiB,CACzB,eAAe,EAAE,eAAe,GAC/B,MAAM,GAAG,SAAS;CAmEtB"}
|
|
@@ -3,20 +3,20 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
3
3
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
4
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
5
|
};
|
|
6
|
-
var _OracleLayer1GasFeeFlow_instances, _OracleLayer1GasFeeFlow_getOracleLayer1GasFee, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee, _OracleLayer1GasFeeFlow_buildUnserializedTransaction, _OracleLayer1GasFeeFlow_buildTransactionParams,
|
|
6
|
+
var _OracleLayer1GasFeeFlow_instances, _OracleLayer1GasFeeFlow_getOracleLayer1GasFee, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee, _OracleLayer1GasFeeFlow_buildUnserializedTransaction, _OracleLayer1GasFeeFlow_buildTransactionParams, _OracleLayer1GasFeeFlow_getGasPriceOracleContract;
|
|
7
7
|
function $importDefault(module) {
|
|
8
8
|
if (module?.__esModule) {
|
|
9
9
|
return module.default;
|
|
10
10
|
}
|
|
11
11
|
return module;
|
|
12
12
|
}
|
|
13
|
-
import {
|
|
13
|
+
import { Contract } from "@ethersproject/contracts";
|
|
14
|
+
import { Web3Provider } from "@ethersproject/providers";
|
|
14
15
|
import { add0x, createModuleLogger } from "@metamask/utils";
|
|
15
16
|
import $BN from "bn.js";
|
|
16
17
|
const BN = $importDefault($BN);
|
|
17
18
|
import { projectLogger } from "../logger.mjs";
|
|
18
19
|
import { prepareTransaction } from "../utils/prepare.mjs";
|
|
19
|
-
import { rpcRequest } from "../utils/provider.mjs";
|
|
20
20
|
import { padHexToEvenLength, toBN } from "../utils/utils.mjs";
|
|
21
21
|
const log = createModuleLogger(projectLogger, 'oracle-layer1-gas-fee-flow');
|
|
22
22
|
const ZERO = new BN(0);
|
|
@@ -64,7 +64,6 @@ const GAS_PRICE_ORACLE_ABI = [
|
|
|
64
64
|
];
|
|
65
65
|
// Default OP Stack gas price oracle address used across supported networks
|
|
66
66
|
const DEFAULT_GAS_PRICE_ORACLE_ADDRESS = '0x420000000000000000000000000000000000000F';
|
|
67
|
-
const GAS_PRICE_ORACLE_INTERFACE = new Interface(GAS_PRICE_ORACLE_ABI);
|
|
68
67
|
/**
|
|
69
68
|
* Layer 1 gas fee flow that obtains gas fee estimate using an oracle smart contract.
|
|
70
69
|
*/
|
|
@@ -103,7 +102,7 @@ export class OracleLayer1GasFeeFlow {
|
|
|
103
102
|
* Defaults to returning the fee unchanged.
|
|
104
103
|
*
|
|
105
104
|
* @param oracleFee - The raw L1 fee returned by the oracle contract.
|
|
106
|
-
* @param _request - The original fee flow request (
|
|
105
|
+
* @param _request - The original fee flow request (provider + transaction).
|
|
107
106
|
* @returns The transformed fee.
|
|
108
107
|
*/
|
|
109
108
|
async transformOracleFee(oracleFee, _request) {
|
|
@@ -111,9 +110,11 @@ export class OracleLayer1GasFeeFlow {
|
|
|
111
110
|
}
|
|
112
111
|
async getLayer1Fee(request) {
|
|
113
112
|
try {
|
|
114
|
-
const
|
|
113
|
+
const { provider, transactionMeta } = request;
|
|
114
|
+
const contract = __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getGasPriceOracleContract).call(this, provider, transactionMeta.chainId);
|
|
115
|
+
const oracleFee = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getOracleLayer1GasFee).call(this, contract, transactionMeta);
|
|
115
116
|
const transformedFee = await this.transformOracleFee(oracleFee, request);
|
|
116
|
-
const operatorFee = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee).call(this,
|
|
117
|
+
const operatorFee = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee).call(this, contract, transactionMeta);
|
|
117
118
|
return {
|
|
118
119
|
layer1Fee: add0x(padHexToEvenLength(transformedFee.add(operatorFee).toString(16))),
|
|
119
120
|
};
|
|
@@ -136,25 +137,21 @@ export class OracleLayer1GasFeeFlow {
|
|
|
136
137
|
return transactionMeta.gasUsed;
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
|
-
_OracleLayer1GasFeeFlow_instances = new WeakSet(), _OracleLayer1GasFeeFlow_getOracleLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOracleLayer1GasFee(
|
|
140
|
-
const serializedTransaction = __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_buildUnserializedTransaction).call(this,
|
|
141
|
-
const result = await
|
|
142
|
-
|
|
143
|
-
]);
|
|
144
|
-
if (typeof result !== 'string' || result === '0x') {
|
|
140
|
+
_OracleLayer1GasFeeFlow_instances = new WeakSet(), _OracleLayer1GasFeeFlow_getOracleLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOracleLayer1GasFee(contract, transactionMeta) {
|
|
141
|
+
const serializedTransaction = __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_buildUnserializedTransaction).call(this, transactionMeta, this.shouldSignTransaction()).serialize();
|
|
142
|
+
const result = await contract.getL1Fee(serializedTransaction);
|
|
143
|
+
if (result === undefined) {
|
|
145
144
|
throw new Error('No value returned from oracle contract');
|
|
146
145
|
}
|
|
147
146
|
return toBN(result);
|
|
148
|
-
}, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee(
|
|
149
|
-
const gas = this.getOperatorFeeGas(
|
|
147
|
+
}, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee(contract, transactionMeta) {
|
|
148
|
+
const gas = this.getOperatorFeeGas(transactionMeta);
|
|
150
149
|
if (!gas) {
|
|
151
150
|
return ZERO;
|
|
152
151
|
}
|
|
153
152
|
try {
|
|
154
|
-
const result = await
|
|
155
|
-
|
|
156
|
-
]);
|
|
157
|
-
if (typeof result !== 'string' || result === '0x') {
|
|
153
|
+
const result = await contract.getOperatorFee(gas);
|
|
154
|
+
if (result === undefined) {
|
|
158
155
|
return ZERO;
|
|
159
156
|
}
|
|
160
157
|
return toBN(result);
|
|
@@ -179,23 +176,9 @@ _OracleLayer1GasFeeFlow_instances = new WeakSet(), _OracleLayer1GasFeeFlow_getOr
|
|
|
179
176
|
...transactionMeta.txParams,
|
|
180
177
|
gasLimit: transactionMeta.txParams.gas,
|
|
181
178
|
};
|
|
182
|
-
},
|
|
183
|
-
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
// when the timer pump is starved (e.g. iOS display link freeze), blocking
|
|
187
|
-
// `addTransaction` indefinitely.
|
|
188
|
-
// See https://github.com/MetaMask/metamask-mobile/issues/32863
|
|
189
|
-
async function _OracleLayer1GasFeeFlow_callGasPriceOracle(request, functionName, args) {
|
|
190
|
-
const { messenger, transactionMeta } = request;
|
|
191
|
-
const { chainId, networkClientId } = transactionMeta;
|
|
192
|
-
const to = this.getOracleAddressForChain(chainId);
|
|
193
|
-
const data = GAS_PRICE_ORACLE_INTERFACE.encodeFunctionData(functionName, args);
|
|
194
|
-
return await rpcRequest({
|
|
195
|
-
messenger,
|
|
196
|
-
networkClientId,
|
|
197
|
-
method: 'eth_call',
|
|
198
|
-
params: [{ to, data }, 'latest'],
|
|
199
|
-
});
|
|
179
|
+
}, _OracleLayer1GasFeeFlow_getGasPriceOracleContract = function _OracleLayer1GasFeeFlow_getGasPriceOracleContract(provider, chainId) {
|
|
180
|
+
return new Contract(this.getOracleAddressForChain(chainId), GAS_PRICE_ORACLE_ABI,
|
|
181
|
+
// Network controller provider type is incompatible with ethers provider
|
|
182
|
+
new Web3Provider(provider));
|
|
200
183
|
};
|
|
201
184
|
//# sourceMappingURL=OracleLayer1GasFeeFlow.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OracleLayer1GasFeeFlow.mjs","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport type { Hex } from '@metamask/utils';\nimport { add0x, createModuleLogger } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type {\n Layer1GasFeeFlow,\n Layer1GasFeeFlowRequest,\n Layer1GasFeeFlowResponse,\n TransactionMeta,\n} from '../types';\nimport { prepareTransaction } from '../utils/prepare';\nimport { rpcRequest } from '../utils/provider';\nimport { padHexToEvenLength, toBN } from '../utils/utils';\n\nconst log = createModuleLogger(projectLogger, 'oracle-layer1-gas-fee-flow');\n\nconst ZERO = new BN(0);\n\nconst DUMMY_KEY =\n 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789';\n\nconst GAS_PRICE_ORACLE_ABI = [\n {\n inputs: [\n {\n internalType: 'bytes',\n name: '_data',\n type: 'bytes',\n },\n ],\n name: 'getL1Fee',\n outputs: [\n {\n internalType: 'uint256',\n name: '',\n type: 'uint256',\n },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n // only available post Isthmus\n {\n inputs: [\n {\n internalType: 'uint256',\n name: '_gasUsed',\n type: 'uint256',\n },\n ],\n name: 'getOperatorFee',\n outputs: [\n {\n internalType: 'uint256',\n name: '',\n type: 'uint256',\n },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n];\n\n// Default OP Stack gas price oracle address used across supported networks\nconst DEFAULT_GAS_PRICE_ORACLE_ADDRESS =\n '0x420000000000000000000000000000000000000F' as Hex;\n\nconst GAS_PRICE_ORACLE_INTERFACE = new Interface(GAS_PRICE_ORACLE_ABI);\n\n/**\n * Layer 1 gas fee flow that obtains gas fee estimate using an oracle smart contract.\n */\nexport abstract class OracleLayer1GasFeeFlow implements Layer1GasFeeFlow {\n /**\n * Resolves the oracle address for the given chain. Subclasses can override\n * this method to provide chain-specific oracle addresses. By default, this\n * returns the standard OP Stack gas price oracle address.\n *\n * @param _chainId - The chain ID to resolve the oracle address for.\n * @returns The oracle address for the given chain.\n */\n protected getOracleAddressForChain(_chainId: Hex): Hex {\n return DEFAULT_GAS_PRICE_ORACLE_ADDRESS;\n }\n\n /**\n * Whether to sign the transaction with a dummy key prior to calling the\n * oracle contract. Some oracle contracts require a signed payload even for\n * read-only methods.\n *\n * Subclasses can override to enable signing when needed. Defaults to false.\n *\n * @returns Whether the transaction should be signed prior to the oracle call.\n */\n protected shouldSignTransaction(): boolean {\n return false;\n }\n\n abstract matchesTransaction({\n transactionMeta,\n messenger,\n }: {\n transactionMeta: TransactionMeta;\n messenger: TransactionControllerMessenger;\n }): Promise<boolean>;\n\n /**\n * Transforms the raw oracle L1 fee before it is combined with the operator\n * fee. Subclasses can override this to apply chain-specific conversions\n * (e.g. currency conversion via an on-chain exchange rate).\n *\n * Defaults to returning the fee unchanged.\n *\n * @param oracleFee - The raw L1 fee returned by the oracle contract.\n * @param _request - The original fee flow request (messenger + transaction).\n * @returns The transformed fee.\n */\n protected async transformOracleFee(\n oracleFee: BN,\n _request: Layer1GasFeeFlowRequest,\n ): Promise<BN> {\n return oracleFee;\n }\n\n async getLayer1Fee(\n request: Layer1GasFeeFlowRequest,\n ): Promise<Layer1GasFeeFlowResponse> {\n try {\n const oracleFee = await this.#getOracleLayer1GasFee(request);\n const transformedFee = await this.transformOracleFee(oracleFee, request);\n const operatorFee = await this.#getOperatorLayer1GasFee(request);\n\n return {\n layer1Fee: add0x(\n padHexToEvenLength(transformedFee.add(operatorFee).toString(16)),\n ),\n };\n } catch (error) {\n log('Failed to get oracle layer 1 gas fee', error);\n throw new Error(`Failed to get oracle layer 1 gas fee`);\n }\n }\n\n async #getOracleLayer1GasFee(request: Layer1GasFeeFlowRequest): Promise<BN> {\n const serializedTransaction = this.#buildUnserializedTransaction(\n request.transactionMeta,\n this.shouldSignTransaction(),\n ).serialize();\n\n const result = await this.#callGasPriceOracle(request, 'getL1Fee', [\n serializedTransaction,\n ]);\n\n if (typeof result !== 'string' || result === '0x') {\n throw new Error('No value returned from oracle contract');\n }\n\n return toBN(result);\n }\n\n /**\n * Returns the gas value to pass to the operator-fee oracle, or undefined\n * to skip the operator-fee call entirely. Defaults to the simulated\n * `gasUsed` on the transaction. Subclasses can override to supply a\n * fallback (e.g. estimated gas limit) when `gasUsed` is unavailable.\n *\n * @param transactionMeta - The transaction metadata.\n * @returns The gas value, or undefined to skip the operator-fee call.\n */\n protected getOperatorFeeGas(\n transactionMeta: TransactionMeta,\n ): string | undefined {\n return transactionMeta.gasUsed;\n }\n\n async #getOperatorLayer1GasFee(\n request: Layer1GasFeeFlowRequest,\n ): Promise<BN> {\n const gas = this.getOperatorFeeGas(request.transactionMeta);\n\n if (!gas) {\n return ZERO;\n }\n\n try {\n const result = await this.#callGasPriceOracle(request, 'getOperatorFee', [\n gas,\n ]);\n\n if (typeof result !== 'string' || result === '0x') {\n return ZERO;\n }\n\n return toBN(result);\n } catch (error) {\n log('Failed to get operator layer 1 gas fee', error);\n return ZERO;\n }\n }\n\n #buildUnserializedTransaction(\n transactionMeta: TransactionMeta,\n sign: boolean,\n ): ReturnType<typeof prepareTransaction> {\n const txParams = this.#buildTransactionParams(transactionMeta);\n const { chainId } = transactionMeta;\n\n let unserializedTransaction = prepareTransaction(chainId, txParams);\n\n if (sign) {\n // eslint-disable-next-line no-restricted-globals\n const keyBuffer = Buffer.from(DUMMY_KEY, 'hex');\n const keyBytes = Uint8Array.from(keyBuffer);\n unserializedTransaction = unserializedTransaction.sign(keyBytes);\n }\n\n return unserializedTransaction;\n }\n\n #buildTransactionParams(\n transactionMeta: TransactionMeta,\n ): TransactionMeta['txParams'] {\n return {\n ...transactionMeta.txParams,\n gasLimit: transactionMeta.txParams.gas,\n };\n }\n\n // The oracle is called via a direct `eth_call` RPC request rather than an\n // ethers `Contract` with `Web3Provider`, as `Web3Provider` schedules its\n // JSON-RPC dispatch with `setTimeout`, which never fires on React Native\n // when the timer pump is starved (e.g. iOS display link freeze), blocking\n // `addTransaction` indefinitely.\n // See https://github.com/MetaMask/metamask-mobile/issues/32863\n async #callGasPriceOracle(\n request: Layer1GasFeeFlowRequest,\n functionName: string,\n args: readonly unknown[],\n ): Promise<unknown> {\n const { messenger, transactionMeta } = request;\n const { chainId, networkClientId } = transactionMeta;\n\n const to = this.getOracleAddressForChain(chainId);\n const data = GAS_PRICE_ORACLE_INTERFACE.encodeFunctionData(\n functionName,\n args,\n ) as Hex;\n\n return await rpcRequest({\n messenger,\n networkClientId,\n method: 'eth_call',\n params: [{ to, data }, 'latest'],\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"OracleLayer1GasFeeFlow.mjs","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"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","sourcesContent":["import { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport type { ExternalProvider } from '@ethersproject/providers';\nimport type { Hex } from '@metamask/utils';\nimport { add0x, createModuleLogger } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { projectLogger } from '../logger';\nimport type { TransactionControllerMessenger } from '../TransactionController';\nimport type {\n Layer1GasFeeFlow,\n Layer1GasFeeFlowRequest,\n Layer1GasFeeFlowResponse,\n TransactionMeta,\n} from '../types';\nimport { prepareTransaction } from '../utils/prepare';\nimport { padHexToEvenLength, toBN } from '../utils/utils';\n\nconst log = createModuleLogger(projectLogger, 'oracle-layer1-gas-fee-flow');\n\nconst ZERO = new BN(0);\n\nconst DUMMY_KEY =\n 'abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789';\n\nconst GAS_PRICE_ORACLE_ABI = [\n {\n inputs: [\n {\n internalType: 'bytes',\n name: '_data',\n type: 'bytes',\n },\n ],\n name: 'getL1Fee',\n outputs: [\n {\n internalType: 'uint256',\n name: '',\n type: 'uint256',\n },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n // only available post Isthmus\n {\n inputs: [\n {\n internalType: 'uint256',\n name: '_gasUsed',\n type: 'uint256',\n },\n ],\n name: 'getOperatorFee',\n outputs: [\n {\n internalType: 'uint256',\n name: '',\n type: 'uint256',\n },\n ],\n stateMutability: 'view',\n type: 'function',\n },\n];\n\n// Default OP Stack gas price oracle address used across supported networks\nconst DEFAULT_GAS_PRICE_ORACLE_ADDRESS =\n '0x420000000000000000000000000000000000000F' as Hex;\n\n/**\n * Layer 1 gas fee flow that obtains gas fee estimate using an oracle smart contract.\n */\nexport abstract class OracleLayer1GasFeeFlow implements Layer1GasFeeFlow {\n /**\n * Resolves the oracle address for the given chain. Subclasses can override\n * this method to provide chain-specific oracle addresses. By default, this\n * returns the standard OP Stack gas price oracle address.\n *\n * @param _chainId - The chain ID to resolve the oracle address for.\n * @returns The oracle address for the given chain.\n */\n protected getOracleAddressForChain(_chainId: Hex): Hex {\n return DEFAULT_GAS_PRICE_ORACLE_ADDRESS;\n }\n\n /**\n * Whether to sign the transaction with a dummy key prior to calling the\n * oracle contract. Some oracle contracts require a signed payload even for\n * read-only methods.\n *\n * Subclasses can override to enable signing when needed. Defaults to false.\n *\n * @returns Whether the transaction should be signed prior to the oracle call.\n */\n protected shouldSignTransaction(): boolean {\n return false;\n }\n\n abstract matchesTransaction({\n transactionMeta,\n messenger,\n }: {\n transactionMeta: TransactionMeta;\n messenger: TransactionControllerMessenger;\n }): Promise<boolean>;\n\n /**\n * Transforms the raw oracle L1 fee before it is combined with the operator\n * fee. Subclasses can override this to apply chain-specific conversions\n * (e.g. currency conversion via an on-chain exchange rate).\n *\n * Defaults to returning the fee unchanged.\n *\n * @param oracleFee - The raw L1 fee returned by the oracle contract.\n * @param _request - The original fee flow request (provider + transaction).\n * @returns The transformed fee.\n */\n protected async transformOracleFee(\n oracleFee: BN,\n _request: Layer1GasFeeFlowRequest,\n ): Promise<BN> {\n return oracleFee;\n }\n\n async getLayer1Fee(\n request: Layer1GasFeeFlowRequest,\n ): Promise<Layer1GasFeeFlowResponse> {\n try {\n const { provider, transactionMeta } = request;\n\n const contract = this.#getGasPriceOracleContract(\n provider,\n transactionMeta.chainId,\n );\n\n const oracleFee = await this.#getOracleLayer1GasFee(\n contract,\n transactionMeta,\n );\n const transformedFee = await this.transformOracleFee(oracleFee, request);\n const operatorFee = await this.#getOperatorLayer1GasFee(\n contract,\n transactionMeta,\n );\n\n return {\n layer1Fee: add0x(\n padHexToEvenLength(transformedFee.add(operatorFee).toString(16)),\n ),\n };\n } catch (error) {\n log('Failed to get oracle layer 1 gas fee', error);\n throw new Error(`Failed to get oracle layer 1 gas fee`);\n }\n }\n\n async #getOracleLayer1GasFee(\n contract: Contract,\n transactionMeta: TransactionMeta,\n ): Promise<BN> {\n const serializedTransaction = this.#buildUnserializedTransaction(\n transactionMeta,\n this.shouldSignTransaction(),\n ).serialize();\n\n const result = await contract.getL1Fee(serializedTransaction);\n\n if (result === undefined) {\n throw new Error('No value returned from oracle contract');\n }\n\n return toBN(result);\n }\n\n /**\n * Returns the gas value to pass to the operator-fee oracle, or undefined\n * to skip the operator-fee call entirely. Defaults to the simulated\n * `gasUsed` on the transaction. Subclasses can override to supply a\n * fallback (e.g. estimated gas limit) when `gasUsed` is unavailable.\n *\n * @param transactionMeta - The transaction metadata.\n * @returns The gas value, or undefined to skip the operator-fee call.\n */\n protected getOperatorFeeGas(\n transactionMeta: TransactionMeta,\n ): string | undefined {\n return transactionMeta.gasUsed;\n }\n\n async #getOperatorLayer1GasFee(\n contract: Contract,\n transactionMeta: TransactionMeta,\n ): Promise<BN> {\n const gas = this.getOperatorFeeGas(transactionMeta);\n\n if (!gas) {\n return ZERO;\n }\n\n try {\n const result = await contract.getOperatorFee(gas);\n\n if (result === undefined) {\n return ZERO;\n }\n\n return toBN(result);\n } catch (error) {\n log('Failed to get operator layer 1 gas fee', error);\n return ZERO;\n }\n }\n\n #buildUnserializedTransaction(\n transactionMeta: TransactionMeta,\n sign: boolean,\n ): ReturnType<typeof prepareTransaction> {\n const txParams = this.#buildTransactionParams(transactionMeta);\n const { chainId } = transactionMeta;\n\n let unserializedTransaction = prepareTransaction(chainId, txParams);\n\n if (sign) {\n // eslint-disable-next-line no-restricted-globals\n const keyBuffer = Buffer.from(DUMMY_KEY, 'hex');\n const keyBytes = Uint8Array.from(keyBuffer);\n unserializedTransaction = unserializedTransaction.sign(keyBytes);\n }\n\n return unserializedTransaction;\n }\n\n #buildTransactionParams(\n transactionMeta: TransactionMeta,\n ): TransactionMeta['txParams'] {\n return {\n ...transactionMeta.txParams,\n gasLimit: transactionMeta.txParams.gas,\n };\n }\n\n #getGasPriceOracleContract(\n provider: Layer1GasFeeFlowRequest['provider'],\n chainId: Hex,\n ): Contract {\n return new Contract(\n this.getOracleAddressForChain(chainId),\n GAS_PRICE_ORACLE_ABI,\n // Network controller provider type is incompatible with ethers provider\n new Web3Provider(provider as unknown as ExternalProvider),\n );\n }\n}\n"]}
|