@@ -2,13 +2,14 @@ import type { TypedTransaction } from '@ethereumjs/tx';
22import { TransactionFactory } from '@ethereumjs/tx' ;
33import { Contract } from '@ethersproject/contracts' ;
44import type { Provider } from '@metamask/network-controller' ;
5- import type { Hex } from '@metamask/utils' ;
6-
7- import { OracleLayer1GasFeeFlow } from './OracleLayer1GasFeeFlow' ;
5+ import { add0x , type Hex } from '@metamask/utils' ;
6+ import BN from 'bn.js' ;
87import { CHAIN_IDS } from '../constants' ;
98import type { TransactionControllerMessenger } from '../TransactionController' ;
109import type { Layer1GasFeeFlowRequest , TransactionMeta } from '../types' ;
1110import { TransactionStatus } from '../types' ;
11+ import { padHexToEvenLength } from '../utils/utils' ;
12+ import { OracleLayer1GasFeeFlow } from './OracleLayer1GasFeeFlow' ;
1213
1314jest . mock ( '@ethersproject/contracts' , ( ) => ( {
1415 Contract : jest . fn ( ) ,
@@ -36,7 +37,8 @@ const TRANSACTION_META_MOCK: TransactionMeta = {
3637
3738const SERIALIZED_TRANSACTION_MOCK = '0x1234' ;
3839const ORACLE_ADDRESS_MOCK = '0x5678' as Hex ;
39- const LAYER_1_FEE_MOCK = '0x9ABCD' ;
40+ const LAYER_1_FEE_MOCK = '0x09abcd' ;
41+ const OPERATOR_FEE_MOCK = '0x5' ;
4042const DEFAULT_GAS_PRICE_ORACLE_ADDRESS =
4143 '0x420000000000000000000000000000000000000F' ;
4244
@@ -98,9 +100,9 @@ class DefaultOracleLayer1GasFeeFlow extends OracleLayer1GasFeeFlow {
98100
99101describe ( 'OracleLayer1GasFeeFlow' , ( ) => {
100102 const contractMock = jest . mocked ( Contract ) ;
101- const contractGetL1FeeMock : jest . MockedFn <
102- ( ) => Promise < { toHexString : ( ) => string } >
103- > = jest . fn ( ) ;
103+ const contractGetL1FeeMock : jest . MockedFn < ( ) => Promise < BN > > = jest . fn ( ) ;
104+ const contractGetOperatorFeeMock : jest . MockedFn < ( ) => Promise < BN > > =
105+ jest . fn ( ) ;
104106
105107 let request : Layer1GasFeeFlowRequest ;
106108
@@ -112,13 +114,14 @@ describe('OracleLayer1GasFeeFlow', () => {
112114
113115 contractMock . mockClear ( ) ;
114116 contractGetL1FeeMock . mockClear ( ) ;
117+ contractGetOperatorFeeMock . mockClear ( ) ;
115118
116- contractGetL1FeeMock . mockResolvedValue ( {
117- toHexString : ( ) => LAYER_1_FEE_MOCK ,
118- } ) ;
119+ contractGetL1FeeMock . mockResolvedValue ( new BN ( LAYER_1_FEE_MOCK ) ) ;
120+ contractGetOperatorFeeMock . mockResolvedValue ( new BN ( 0 ) ) ;
119121
120122 contractMock . mockReturnValue ( {
121123 getL1Fee : contractGetL1FeeMock ,
124+ getOperatorFee : contractGetOperatorFeeMock ,
122125 } as unknown as Contract ) ;
123126 } ) ;
124127
@@ -156,6 +159,7 @@ describe('OracleLayer1GasFeeFlow', () => {
156159 expect ( contractGetL1FeeMock ) . toHaveBeenCalledWith (
157160 serializedTransactionMock ,
158161 ) ;
162+ expect ( contractGetOperatorFeeMock ) . not . toHaveBeenCalled ( ) ;
159163 } ) ;
160164
161165 it ( 'signs transaction with dummy key if supported by flow' , async ( ) => {
@@ -180,6 +184,7 @@ describe('OracleLayer1GasFeeFlow', () => {
180184 } ) ;
181185
182186 expect ( typedTransactionMock . sign ) . toHaveBeenCalledTimes ( 1 ) ;
187+ expect ( contractGetOperatorFeeMock ) . not . toHaveBeenCalled ( ) ;
183188 } ) ;
184189
185190 describe ( 'throws' , ( ) => {
@@ -228,5 +233,79 @@ describe('OracleLayer1GasFeeFlow', () => {
228233 expect ( oracleAddress ) . toBe ( DEFAULT_GAS_PRICE_ORACLE_ADDRESS ) ;
229234 expect ( typedTransactionMock . sign ) . not . toHaveBeenCalled ( ) ;
230235 } ) ;
236+
237+ it ( 'adds operator fee when gas used is available' , async ( ) => {
238+ const gasUsed = '0x5208' ;
239+ request = {
240+ ...request ,
241+ transactionMeta : {
242+ ...request . transactionMeta ,
243+ gasUsed,
244+ } ,
245+ } ;
246+
247+ contractGetOperatorFeeMock . mockResolvedValueOnce (
248+ new BN ( OPERATOR_FEE_MOCK ) ,
249+ ) ;
250+
251+ const flow = new MockOracleLayer1GasFeeFlow ( false ) ;
252+ const response = await flow . getLayer1Fee ( request ) ;
253+
254+ expect ( contractGetOperatorFeeMock ) . toHaveBeenCalledTimes ( 1 ) ;
255+ expect ( contractGetOperatorFeeMock ) . toHaveBeenCalledWith ( gasUsed ) ;
256+ expect ( response ) . toStrictEqual ( {
257+ layer1Fee : add0x (
258+ padHexToEvenLength (
259+ new BN ( LAYER_1_FEE_MOCK )
260+ . add ( new BN ( OPERATOR_FEE_MOCK ) )
261+ . toString ( 16 ) ,
262+ ) ,
263+ ) as Hex ,
264+ } ) ;
265+ } ) ;
266+
267+ it ( 'defaults operator fee to zero when call fails' , async ( ) => {
268+ const gasUsed = '0x1' ;
269+ request = {
270+ ...request ,
271+ transactionMeta : {
272+ ...request . transactionMeta ,
273+ gasUsed,
274+ } ,
275+ } ;
276+
277+ contractGetOperatorFeeMock . mockRejectedValueOnce ( new Error ( 'revert' ) ) ;
278+
279+ const flow = new MockOracleLayer1GasFeeFlow ( false ) ;
280+ const response = await flow . getLayer1Fee ( request ) ;
281+
282+ expect ( contractGetOperatorFeeMock ) . toHaveBeenCalledTimes ( 1 ) ;
283+ expect ( response ) . toStrictEqual ( {
284+ layer1Fee : LAYER_1_FEE_MOCK ,
285+ } ) ;
286+ } ) ;
287+
288+ it ( 'defaults operator fee to zero when call returns undefined' , async ( ) => {
289+ const gasUsed = '0x2' ;
290+ request = {
291+ ...request ,
292+ transactionMeta : {
293+ ...request . transactionMeta ,
294+ gasUsed,
295+ } ,
296+ } ;
297+
298+ contractGetOperatorFeeMock . mockResolvedValueOnce (
299+ undefined as unknown as BN ,
300+ ) ;
301+
302+ const flow = new MockOracleLayer1GasFeeFlow ( false ) ;
303+ const response = await flow . getLayer1Fee ( request ) ;
304+
305+ expect ( contractGetOperatorFeeMock ) . toHaveBeenCalledTimes ( 1 ) ;
306+ expect ( response ) . toStrictEqual ( {
307+ layer1Fee : LAYER_1_FEE_MOCK ,
308+ } ) ;
309+ } ) ;
231310 } ) ;
232311} ) ;
0 commit comments