@metamask/transaction-controller 69.0.0 → 69.2.0

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/LICENSE +1 -0
  3. package/dist/gas-flows/MantleLayer1GasFeeFlow.cjs +21 -6
  4. package/dist/gas-flows/MantleLayer1GasFeeFlow.cjs.map +1 -1
  5. package/dist/gas-flows/MantleLayer1GasFeeFlow.d.cts.map +1 -1
  6. package/dist/gas-flows/MantleLayer1GasFeeFlow.d.mts.map +1 -1
  7. package/dist/gas-flows/MantleLayer1GasFeeFlow.mjs +21 -6
  8. package/dist/gas-flows/MantleLayer1GasFeeFlow.mjs.map +1 -1
  9. package/dist/gas-flows/OracleLayer1GasFeeFlow.cjs +37 -20
  10. package/dist/gas-flows/OracleLayer1GasFeeFlow.cjs.map +1 -1
  11. package/dist/gas-flows/OracleLayer1GasFeeFlow.d.cts +1 -1
  12. package/dist/gas-flows/OracleLayer1GasFeeFlow.d.cts.map +1 -1
  13. package/dist/gas-flows/OracleLayer1GasFeeFlow.d.mts +1 -1
  14. package/dist/gas-flows/OracleLayer1GasFeeFlow.d.mts.map +1 -1
  15. package/dist/gas-flows/OracleLayer1GasFeeFlow.mjs +37 -20
  16. package/dist/gas-flows/OracleLayer1GasFeeFlow.mjs.map +1 -1
  17. package/dist/index.cjs +3 -1
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +1 -0
  20. package/dist/index.d.cts.map +1 -1
  21. package/dist/index.d.mts +1 -0
  22. package/dist/index.d.mts.map +1 -1
  23. package/dist/index.mjs +1 -0
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/types.cjs.map +1 -1
  26. package/dist/types.d.cts +3 -3
  27. package/dist/types.d.cts.map +1 -1
  28. package/dist/types.d.mts +3 -3
  29. package/dist/types.d.mts.map +1 -1
  30. package/dist/types.mjs.map +1 -1
  31. package/dist/utils/layer1-gas-fee-flow.cjs +1 -6
  32. package/dist/utils/layer1-gas-fee-flow.cjs.map +1 -1
  33. package/dist/utils/layer1-gas-fee-flow.d.cts.map +1 -1
  34. package/dist/utils/layer1-gas-fee-flow.d.mts.map +1 -1
  35. package/dist/utils/layer1-gas-fee-flow.mjs +1 -6
  36. package/dist/utils/layer1-gas-fee-flow.mjs.map +1 -1
  37. package/dist/utils/transaction-type.cjs +17 -1
  38. package/dist/utils/transaction-type.cjs.map +1 -1
  39. package/dist/utils/transaction-type.d.cts +11 -1
  40. package/dist/utils/transaction-type.d.cts.map +1 -1
  41. package/dist/utils/transaction-type.d.mts +11 -1
  42. package/dist/utils/transaction-type.d.mts.map +1 -1
  43. package/dist/utils/transaction-type.mjs +15 -0
  44. package/dist/utils/transaction-type.mjs.map +1 -1
  45. package/package.json +3 -2
package/CHANGELOG.md CHANGED
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [69.2.0]
11
+
12
+ ### Added
13
+
14
+ - Export `hasTransactionType` helper for checking a transaction's type against the top-level `TransactionMeta` and any nested transactions ([#9570](https://github.com/MetaMask/core/pull/9570))
15
+
16
+ ## [69.1.0]
17
+
18
+ ### Changed
19
+
20
+ - 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))
21
+ - `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))
22
+
10
23
  ## [69.0.0]
11
24
 
12
25
  ### Changed
@@ -2584,7 +2597,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2584
2597
 
2585
2598
  All changes listed after this point were applied to this package following the monorepo conversion.
2586
2599
 
2587
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@69.0.0...HEAD
2600
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@69.2.0...HEAD
2601
+ [69.2.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@69.1.0...@metamask/transaction-controller@69.2.0
2602
+ [69.1.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@69.0.0...@metamask/transaction-controller@69.1.0
2588
2603
  [69.0.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@68.4.0...@metamask/transaction-controller@69.0.0
2589
2604
  [68.4.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@68.3.0...@metamask/transaction-controller@68.4.0
2590
2605
  [68.3.0]: https://github.com/MetaMask/core/compare/@metamask/transaction-controller@68.2.2...@metamask/transaction-controller@68.3.0
package/LICENSE CHANGED
@@ -18,3 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MantleLayer1GasFeeFlow = void 0;
4
- const contracts_1 = require("@ethersproject/contracts");
5
- const providers_1 = require("@ethersproject/providers");
4
+ const abi_1 = require("@ethersproject/abi");
6
5
  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,6 +22,7 @@ const TOKEN_RATIO_ABI = [
22
22
  type: 'function',
23
23
  },
24
24
  ];
25
+ const TOKEN_RATIO_INTERFACE = new abi_1.Interface(TOKEN_RATIO_ABI);
25
26
  /**
26
27
  * Mantle layer 1 gas fee flow.
27
28
  *
@@ -40,10 +41,24 @@ class MantleLayer1GasFeeFlow extends OracleLayer1GasFeeFlow_1.OracleLayer1GasFee
40
41
  transactionMeta.txParams.gasLimit);
41
42
  }
42
43
  async transformOracleFee(oracleFee, request) {
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());
44
+ const { messenger, transactionMeta } = request;
45
+ const { chainId, networkClientId } = transactionMeta;
46
+ const to = this.getOracleAddressForChain(chainId);
47
+ const data = TOKEN_RATIO_INTERFACE.encodeFunctionData('tokenRatio', []);
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);
47
62
  return oracleFee.mul(tokenRatio);
48
63
  }
49
64
  }
@@ -1 +1 @@
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
+ {"version":3,"file":"MantleLayer1GasFeeFlow.cjs","sourceRoot":"","sources":["../../src/gas-flows/MantleLayer1GasFeeFlow.ts"],"names":[],"mappings":";;;AAAA,4CAA+C;AAI/C,gDAAyC;AAGzC,oDAA+C;AAC/C,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,MAAM,qBAAqB,GAAG,IAAI,eAAS,CAAC,eAAe,CAAC,CAAC;AAE7D;;;;;;;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,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;QAC/C,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,eAAe,CAAC;QAErD,MAAM,EAAE,GAAG,IAAI,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,qBAAqB,CAAC,kBAAkB,CACnD,YAAY,EACZ,EAAE,CACI,CAAC;QAET,sEAAsE;QACtE,yEAAyE;QACzE,wEAAwE;QACxE,+DAA+D;QAC/D,MAAM,MAAM,GAAG,MAAM,IAAA,qBAAU,EAAC;YAC9B,SAAS;YACT,eAAe;YACf,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC;SACjC,CAAC,CAAC;QAEH,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QAED,MAAM,UAAU,GAAG,IAAA,YAAI,EAAC,MAAM,CAAC,CAAC;QAChC,OAAO,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;CACF;AAnDD,wDAmDC","sourcesContent":["import { Interface } from '@ethersproject/abi';\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 { rpcRequest } from '../utils/provider';\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\nconst TOKEN_RATIO_INTERFACE = new Interface(TOKEN_RATIO_ABI);\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 { messenger, transactionMeta } = request;\n const { chainId, networkClientId } = transactionMeta;\n\n const to = this.getOracleAddressForChain(chainId);\n const data = TOKEN_RATIO_INTERFACE.encodeFunctionData(\n 'tokenRatio',\n [],\n ) as Hex;\n\n // Direct `eth_call` RPC request rather than an ethers `Contract` with\n // `Web3Provider`, whose `setTimeout`-based dispatch never fires on React\n // Native when the timer pump is starved (e.g. iOS display link freeze).\n // See https://github.com/MetaMask/metamask-mobile/issues/32863\n const result = await rpcRequest({\n messenger,\n networkClientId,\n method: 'eth_call',\n params: [{ to, data }, 'latest'],\n });\n\n if (typeof result !== 'string' || result === '0x') {\n throw new Error('No value returned from token ratio contract');\n }\n\n const tokenRatio = toBN(result);\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":"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
+ {"version":3,"file":"MantleLayer1GasFeeFlow.d.cts","sourceRoot":"","sources":["../../src/gas-flows/MantleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc;AAG5B,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EAAE,uBAAuB,EAAE,eAAe,EAAE,qBAAiB;AAGzE,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAsBlE;;;;;;;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;CA4Bf"}
@@ -1 +1 @@
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
+ {"version":3,"file":"MantleLayer1GasFeeFlow.d.mts","sourceRoot":"","sources":["../../src/gas-flows/MantleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc;AAG5B,OAAO,KAAK,EAAE,8BAA8B,EAAE,qCAAiC;AAC/E,OAAO,KAAK,EAAE,uBAAuB,EAAE,eAAe,EAAE,qBAAiB;AAGzE,OAAO,EAAE,sBAAsB,EAAE,qCAAiC;AAsBlE;;;;;;;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;CA4Bf"}
@@ -1,6 +1,6 @@
1
- import { Contract } from "@ethersproject/contracts";
2
- import { Web3Provider } from "@ethersproject/providers";
1
+ import { Interface } from "@ethersproject/abi";
3
2
  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,6 +19,7 @@ const TOKEN_RATIO_ABI = [
19
19
  type: 'function',
20
20
  },
21
21
  ];
22
+ const TOKEN_RATIO_INTERFACE = new Interface(TOKEN_RATIO_ABI);
22
23
  /**
23
24
  * Mantle layer 1 gas fee flow.
24
25
  *
@@ -37,10 +38,24 @@ export class MantleLayer1GasFeeFlow extends OracleLayer1GasFeeFlow {
37
38
  transactionMeta.txParams.gasLimit);
38
39
  }
39
40
  async transformOracleFee(oracleFee, request) {
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());
41
+ const { messenger, transactionMeta } = request;
42
+ const { chainId, networkClientId } = transactionMeta;
43
+ const to = this.getOracleAddressForChain(chainId);
44
+ const data = TOKEN_RATIO_INTERFACE.encodeFunctionData('tokenRatio', []);
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);
44
59
  return oracleFee.mul(tokenRatio);
45
60
  }
46
61
  }
@@ -1 +1 @@
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"]}
1
+ {"version":3,"file":"MantleLayer1GasFeeFlow.mjs","sourceRoot":"","sources":["../../src/gas-flows/MantleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,2BAA2B;AAI/C,OAAO,EAAE,SAAS,EAAE,yBAAqB;AAGzC,OAAO,EAAE,UAAU,EAAE,8BAA0B;AAC/C,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,MAAM,qBAAqB,GAAG,IAAI,SAAS,CAAC,eAAe,CAAC,CAAC;AAE7D;;;;;;;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,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;QAC/C,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,eAAe,CAAC;QAErD,MAAM,EAAE,GAAG,IAAI,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,qBAAqB,CAAC,kBAAkB,CACnD,YAAY,EACZ,EAAE,CACI,CAAC;QAET,sEAAsE;QACtE,yEAAyE;QACzE,wEAAwE;QACxE,+DAA+D;QAC/D,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC;YAC9B,SAAS;YACT,eAAe;YACf,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC;SACjC,CAAC,CAAC;QAEH,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAChC,OAAO,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;CACF","sourcesContent":["import { Interface } from '@ethersproject/abi';\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 { rpcRequest } from '../utils/provider';\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\nconst TOKEN_RATIO_INTERFACE = new Interface(TOKEN_RATIO_ABI);\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 { messenger, transactionMeta } = request;\n const { chainId, networkClientId } = transactionMeta;\n\n const to = this.getOracleAddressForChain(chainId);\n const data = TOKEN_RATIO_INTERFACE.encodeFunctionData(\n 'tokenRatio',\n [],\n ) as Hex;\n\n // Direct `eth_call` RPC request rather than an ethers `Contract` with\n // `Web3Provider`, whose `setTimeout`-based dispatch never fires on React\n // Native when the timer pump is starved (e.g. iOS display link freeze).\n // See https://github.com/MetaMask/metamask-mobile/issues/32863\n const result = await rpcRequest({\n messenger,\n networkClientId,\n method: 'eth_call',\n params: [{ to, data }, 'latest'],\n });\n\n if (typeof result !== 'string' || result === '0x') {\n throw new Error('No value returned from token ratio contract');\n }\n\n const tokenRatio = toBN(result);\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, _OracleLayer1GasFeeFlow_getGasPriceOracleContract;
10
+ var _OracleLayer1GasFeeFlow_instances, _OracleLayer1GasFeeFlow_getOracleLayer1GasFee, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee, _OracleLayer1GasFeeFlow_buildUnserializedTransaction, _OracleLayer1GasFeeFlow_buildTransactionParams, _OracleLayer1GasFeeFlow_callGasPriceOracle;
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.OracleLayer1GasFeeFlow = void 0;
13
- const contracts_1 = require("@ethersproject/contracts");
14
- const providers_1 = require("@ethersproject/providers");
13
+ const abi_1 = require("@ethersproject/abi");
15
14
  const utils_1 = require("@metamask/utils");
16
15
  const bn_js_1 = __importDefault(require("bn.js"));
17
16
  const logger_1 = require("../logger.cjs");
18
17
  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,6 +63,7 @@ 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);
66
67
  /**
67
68
  * Layer 1 gas fee flow that obtains gas fee estimate using an oracle smart contract.
68
69
  */
@@ -101,7 +102,7 @@ class OracleLayer1GasFeeFlow {
101
102
  * Defaults to returning the fee unchanged.
102
103
  *
103
104
  * @param oracleFee - The raw L1 fee returned by the oracle contract.
104
- * @param _request - The original fee flow request (provider + transaction).
105
+ * @param _request - The original fee flow request (messenger + transaction).
105
106
  * @returns The transformed fee.
106
107
  */
107
108
  async transformOracleFee(oracleFee, _request) {
@@ -109,11 +110,9 @@ class OracleLayer1GasFeeFlow {
109
110
  }
110
111
  async getLayer1Fee(request) {
111
112
  try {
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);
113
+ const oracleFee = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getOracleLayer1GasFee).call(this, request);
115
114
  const transformedFee = await this.transformOracleFee(oracleFee, request);
116
- const operatorFee = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee).call(this, contract, transactionMeta);
115
+ const operatorFee = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee).call(this, request);
117
116
  return {
118
117
  layer1Fee: (0, utils_1.add0x)((0, utils_2.padHexToEvenLength)(transformedFee.add(operatorFee).toString(16))),
119
118
  };
@@ -137,21 +136,25 @@ class OracleLayer1GasFeeFlow {
137
136
  }
138
137
  }
139
138
  exports.OracleLayer1GasFeeFlow = OracleLayer1GasFeeFlow;
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) {
139
+ _OracleLayer1GasFeeFlow_instances = new WeakSet(), _OracleLayer1GasFeeFlow_getOracleLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOracleLayer1GasFee(request) {
140
+ const serializedTransaction = __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_buildUnserializedTransaction).call(this, request.transactionMeta, this.shouldSignTransaction()).serialize();
141
+ const result = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_callGasPriceOracle).call(this, request, 'getL1Fee', [
142
+ serializedTransaction,
143
+ ]);
144
+ if (typeof result !== 'string' || result === '0x') {
144
145
  throw new Error('No value returned from oracle contract');
145
146
  }
146
147
  return (0, utils_2.toBN)(result);
147
- }, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee(contract, transactionMeta) {
148
- const gas = this.getOperatorFeeGas(transactionMeta);
148
+ }, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee(request) {
149
+ const gas = this.getOperatorFeeGas(request.transactionMeta);
149
150
  if (!gas) {
150
151
  return ZERO;
151
152
  }
152
153
  try {
153
- const result = await contract.getOperatorFee(gas);
154
- if (result === undefined) {
154
+ const result = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_callGasPriceOracle).call(this, request, 'getOperatorFee', [
155
+ gas,
156
+ ]);
157
+ if (typeof result !== 'string' || result === '0x') {
155
158
  return ZERO;
156
159
  }
157
160
  return (0, utils_2.toBN)(result);
@@ -176,9 +179,23 @@ _OracleLayer1GasFeeFlow_instances = new WeakSet(), _OracleLayer1GasFeeFlow_getOr
176
179
  ...transactionMeta.txParams,
177
180
  gasLimit: transactionMeta.txParams.gas,
178
181
  };
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));
182
+ }, _OracleLayer1GasFeeFlow_callGasPriceOracle =
183
+ // The oracle is called via a direct `eth_call` RPC request rather than an
184
+ // ethers `Contract` with `Web3Provider`, as `Web3Provider` schedules its
185
+ // JSON-RPC dispatch with `setTimeout`, which never fires on React Native
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
+ });
183
200
  };
184
201
  //# 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 { 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"]}
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"]}
@@ -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 (provider + transaction).
41
+ * @param _request - The original fee flow request (messenger + 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":"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"}
1
+ {"version":3,"file":"OracleLayer1GasFeeFlow.d.cts","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AACA,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;AA4DlB;;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;IAkCpC;;;;;;;;OAQG;IACH,SAAS,CAAC,iBAAiB,CACzB,eAAe,EAAE,eAAe,GAC/B,MAAM,GAAG,SAAS;CAoFtB"}
@@ -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 (provider + transaction).
41
+ * @param _request - The original fee flow request (messenger + 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":"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"}
1
+ {"version":3,"file":"OracleLayer1GasFeeFlow.d.mts","sourceRoot":"","sources":["../../src/gas-flows/OracleLayer1GasFeeFlow.ts"],"names":[],"mappings":"AACA,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;AA4DlB;;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;IAkCpC;;;;;;;;OAQG;IACH,SAAS,CAAC,iBAAiB,CACzB,eAAe,EAAE,eAAe,GAC/B,MAAM,GAAG,SAAS;CAoFtB"}
@@ -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, _OracleLayer1GasFeeFlow_getGasPriceOracleContract;
6
+ var _OracleLayer1GasFeeFlow_instances, _OracleLayer1GasFeeFlow_getOracleLayer1GasFee, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee, _OracleLayer1GasFeeFlow_buildUnserializedTransaction, _OracleLayer1GasFeeFlow_buildTransactionParams, _OracleLayer1GasFeeFlow_callGasPriceOracle;
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 { Contract } from "@ethersproject/contracts";
14
- import { Web3Provider } from "@ethersproject/providers";
13
+ import { Interface } from "@ethersproject/abi";
15
14
  import { add0x, createModuleLogger } from "@metamask/utils";
16
15
  import $BN from "bn.js";
17
16
  const BN = $importDefault($BN);
18
17
  import { projectLogger } from "../logger.mjs";
19
18
  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,6 +64,7 @@ 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);
67
68
  /**
68
69
  * Layer 1 gas fee flow that obtains gas fee estimate using an oracle smart contract.
69
70
  */
@@ -102,7 +103,7 @@ export class OracleLayer1GasFeeFlow {
102
103
  * Defaults to returning the fee unchanged.
103
104
  *
104
105
  * @param oracleFee - The raw L1 fee returned by the oracle contract.
105
- * @param _request - The original fee flow request (provider + transaction).
106
+ * @param _request - The original fee flow request (messenger + transaction).
106
107
  * @returns The transformed fee.
107
108
  */
108
109
  async transformOracleFee(oracleFee, _request) {
@@ -110,11 +111,9 @@ export class OracleLayer1GasFeeFlow {
110
111
  }
111
112
  async getLayer1Fee(request) {
112
113
  try {
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);
114
+ const oracleFee = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getOracleLayer1GasFee).call(this, request);
116
115
  const transformedFee = await this.transformOracleFee(oracleFee, request);
117
- const operatorFee = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee).call(this, contract, transactionMeta);
116
+ const operatorFee = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee).call(this, request);
118
117
  return {
119
118
  layer1Fee: add0x(padHexToEvenLength(transformedFee.add(operatorFee).toString(16))),
120
119
  };
@@ -137,21 +136,25 @@ export class OracleLayer1GasFeeFlow {
137
136
  return transactionMeta.gasUsed;
138
137
  }
139
138
  }
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) {
139
+ _OracleLayer1GasFeeFlow_instances = new WeakSet(), _OracleLayer1GasFeeFlow_getOracleLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOracleLayer1GasFee(request) {
140
+ const serializedTransaction = __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_buildUnserializedTransaction).call(this, request.transactionMeta, this.shouldSignTransaction()).serialize();
141
+ const result = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_callGasPriceOracle).call(this, request, 'getL1Fee', [
142
+ serializedTransaction,
143
+ ]);
144
+ if (typeof result !== 'string' || result === '0x') {
144
145
  throw new Error('No value returned from oracle contract');
145
146
  }
146
147
  return toBN(result);
147
- }, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee(contract, transactionMeta) {
148
- const gas = this.getOperatorFeeGas(transactionMeta);
148
+ }, _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee = async function _OracleLayer1GasFeeFlow_getOperatorLayer1GasFee(request) {
149
+ const gas = this.getOperatorFeeGas(request.transactionMeta);
149
150
  if (!gas) {
150
151
  return ZERO;
151
152
  }
152
153
  try {
153
- const result = await contract.getOperatorFee(gas);
154
- if (result === undefined) {
154
+ const result = await __classPrivateFieldGet(this, _OracleLayer1GasFeeFlow_instances, "m", _OracleLayer1GasFeeFlow_callGasPriceOracle).call(this, request, 'getOperatorFee', [
155
+ gas,
156
+ ]);
157
+ if (typeof result !== 'string' || result === '0x') {
155
158
  return ZERO;
156
159
  }
157
160
  return toBN(result);
@@ -176,9 +179,23 @@ _OracleLayer1GasFeeFlow_instances = new WeakSet(), _OracleLayer1GasFeeFlow_getOr
176
179
  ...transactionMeta.txParams,
177
180
  gasLimit: transactionMeta.txParams.gas,
178
181
  };
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));
182
+ }, _OracleLayer1GasFeeFlow_callGasPriceOracle =
183
+ // The oracle is called via a direct `eth_call` RPC request rather than an
184
+ // ethers `Contract` with `Web3Provider`, as `Web3Provider` schedules its
185
+ // JSON-RPC dispatch with `setTimeout`, which never fires on React Native
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
+ });
183
200
  };
184
201
  //# 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 { 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"]}
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"]}
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateBatchId = exports.getAccountAddressRelationship = exports.HARDFORK = exports.CHAIN_IDS = exports.normalizeTransactionParams = exports.isEIP1559Transaction = exports.generateEIP7702BatchTransaction = exports.decodeAuthorizationSignature = exports.mergeGasFeeEstimates = exports.WalletDevice = exports.UserFeeLevel = exports.TransactionType = exports.TransactionStatus = exports.TransactionEnvelopeType = exports.TransactionContainerType = exports.SimulationTokenStandard = exports.SimulationErrorCode = exports.GasFeeEstimateType = exports.GasFeeEstimateLevel = exports.TransactionController = exports.SPEED_UP_RATE = exports.CANCEL_RATE = void 0;
3
+ exports.generateBatchId = exports.getAccountAddressRelationship = exports.HARDFORK = exports.CHAIN_IDS = exports.hasTransactionType = exports.normalizeTransactionParams = exports.isEIP1559Transaction = exports.generateEIP7702BatchTransaction = exports.decodeAuthorizationSignature = exports.mergeGasFeeEstimates = exports.WalletDevice = exports.UserFeeLevel = exports.TransactionType = exports.TransactionStatus = exports.TransactionEnvelopeType = exports.TransactionContainerType = exports.SimulationTokenStandard = exports.SimulationErrorCode = exports.GasFeeEstimateType = exports.GasFeeEstimateLevel = exports.TransactionController = exports.SPEED_UP_RATE = exports.CANCEL_RATE = void 0;
4
4
  var TransactionController_1 = require("./TransactionController.cjs");
5
5
  Object.defineProperty(exports, "CANCEL_RATE", { enumerable: true, get: function () { return TransactionController_1.CANCEL_RATE; } });
6
6
  Object.defineProperty(exports, "SPEED_UP_RATE", { enumerable: true, get: function () { return TransactionController_1.SPEED_UP_RATE; } });
@@ -24,6 +24,8 @@ Object.defineProperty(exports, "generateEIP7702BatchTransaction", { enumerable:
24
24
  var utils_1 = require("./utils/utils.cjs");
25
25
  Object.defineProperty(exports, "isEIP1559Transaction", { enumerable: true, get: function () { return utils_1.isEIP1559Transaction; } });
26
26
  Object.defineProperty(exports, "normalizeTransactionParams", { enumerable: true, get: function () { return utils_1.normalizeTransactionParams; } });
27
+ var transaction_type_1 = require("./utils/transaction-type.cjs");
28
+ Object.defineProperty(exports, "hasTransactionType", { enumerable: true, get: function () { return transaction_type_1.hasTransactionType; } });
27
29
  var constants_1 = require("./constants.cjs");
28
30
  Object.defineProperty(exports, "CHAIN_IDS", { enumerable: true, get: function () { return constants_1.CHAIN_IDS; } });
29
31
  var prepare_1 = require("./utils/prepare.cjs");