@@ -2,13 +2,15 @@ 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' ;
5+ import { add0x , type Hex } from '@metamask/utils' ;
6+ import BN from 'bn.js' ;
67
7- import { OracleLayer1GasFeeFlow } from './OracleLayer1GasFeeFlow' ;
88import { CHAIN_IDS } from '../constants' ;
99import type { TransactionControllerMessenger } from '../TransactionController' ;
1010import type { Layer1GasFeeFlowRequest , TransactionMeta } from '../types' ;
1111import { TransactionStatus } from '../types' ;
12+ import { bnFromHex , padHexToEvenLength } from '../utils/utils' ;
13+ import { OracleLayer1GasFeeFlow } from './OracleLayer1GasFeeFlow' ;
1214
1315jest . mock ( '@ethersproject/contracts' , ( ) => ( {
1416 Contract : jest . fn ( ) ,
@@ -36,7 +38,8 @@ const TRANSACTION_META_MOCK: TransactionMeta = {
3638
3739const SERIALIZED_TRANSACTION_MOCK = '0x1234' ;
3840const ORACLE_ADDRESS_MOCK = '0x5678' as Hex ;
39- const LAYER_1_FEE_MOCK = '0x9ABCD' ;
41+ const LAYER_1_FEE_MOCK = '0x09abcd' ;
42+ const OPERATOR_FEE_MOCK = '0x5' ;
4043const DEFAULT_GAS_PRICE_ORACLE_ADDRESS =
4144 '0x420000000000000000000000000000000000000F' ;
4245
@@ -98,9 +101,9 @@ class DefaultOracleLayer1GasFeeFlow extends OracleLayer1GasFeeFlow {
98101
99102describe ( 'OracleLayer1GasFeeFlow' , ( ) => {
100103 const contractMock = jest . mocked ( Contract ) ;
101- const contractGetL1FeeMock : jest . MockedFn <
102- ( ) => Promise < { toHexString : ( ) => string } >
103- > = jest . fn ( ) ;
104+ const contractGetL1FeeMock : jest . MockedFn < ( ) => Promise < BN > > = jest . fn ( ) ;
105+ const contractGetOperatorFeeMock : jest . MockedFn < ( ) => Promise < BN > > =
106+ jest . fn ( ) ;
104107
105108 let request : Layer1GasFeeFlowRequest ;
106109
@@ -112,13 +115,14 @@ describe('OracleLayer1GasFeeFlow', () => {
112115
113116 contractMock . mockClear ( ) ;
114117 contractGetL1FeeMock . mockClear ( ) ;
118+ contractGetOperatorFeeMock . mockClear ( ) ;
115119
116- contractGetL1FeeMock . mockResolvedValue ( {
117- toHexString : ( ) => LAYER_1_FEE_MOCK ,
118- } ) ;
120+ contractGetL1FeeMock . mockResolvedValue ( bnFromHex ( LAYER_1_FEE_MOCK ) ) ;
121+ contractGetOperatorFeeMock . mockResolvedValue ( new BN ( 0 ) ) ;
119122
120123 contractMock . mockReturnValue ( {
121124 getL1Fee : contractGetL1FeeMock ,
125+ getOperatorFee : contractGetOperatorFeeMock ,
122126 } as unknown as Contract ) ;
123127 } ) ;
124128
@@ -156,6 +160,7 @@ describe('OracleLayer1GasFeeFlow', () => {
156160 expect ( contractGetL1FeeMock ) . toHaveBeenCalledWith (
157161 serializedTransactionMock ,
158162 ) ;
163+ expect ( contractGetOperatorFeeMock ) . not . toHaveBeenCalled ( ) ;
159164 } ) ;
160165
161166 it ( 'signs transaction with dummy key if supported by flow' , async ( ) => {
@@ -180,6 +185,7 @@ describe('OracleLayer1GasFeeFlow', () => {
180185 } ) ;
181186
182187 expect ( typedTransactionMock . sign ) . toHaveBeenCalledTimes ( 1 ) ;
188+ expect ( contractGetOperatorFeeMock ) . not . toHaveBeenCalled ( ) ;
183189 } ) ;
184190
185191 describe ( 'throws' , ( ) => {
@@ -228,5 +234,79 @@ describe('OracleLayer1GasFeeFlow', () => {
228234 expect ( oracleAddress ) . toBe ( DEFAULT_GAS_PRICE_ORACLE_ADDRESS ) ;
229235 expect ( typedTransactionMock . sign ) . not . toHaveBeenCalled ( ) ;
230236 } ) ;
237+
238+ it ( 'adds operator fee when gas used is available' , async ( ) => {
239+ const gasUsed = '0x5208' ;
240+ request = {
241+ ...request ,
242+ transactionMeta : {
243+ ...request . transactionMeta ,
244+ gasUsed,
245+ } ,
246+ } ;
247+
248+ contractGetOperatorFeeMock . mockResolvedValueOnce (
249+ bnFromHex ( OPERATOR_FEE_MOCK ) ,
250+ ) ;
251+
252+ const flow = new MockOracleLayer1GasFeeFlow ( false ) ;
253+ const response = await flow . getLayer1Fee ( request ) ;
254+
255+ expect ( contractGetOperatorFeeMock ) . toHaveBeenCalledTimes ( 1 ) ;
256+ expect ( contractGetOperatorFeeMock ) . toHaveBeenCalledWith ( gasUsed ) ;
257+ expect ( response ) . toStrictEqual ( {
258+ layer1Fee : add0x (
259+ padHexToEvenLength (
260+ bnFromHex ( LAYER_1_FEE_MOCK )
261+ . add ( bnFromHex ( OPERATOR_FEE_MOCK ) )
262+ . toString ( 16 ) ,
263+ ) ,
264+ ) as Hex ,
265+ } ) ;
266+ } ) ;
267+
268+ it ( 'defaults operator fee to zero when call fails' , async ( ) => {
269+ const gasUsed = '0x1' ;
270+ request = {
271+ ...request ,
272+ transactionMeta : {
273+ ...request . transactionMeta ,
274+ gasUsed,
275+ } ,
276+ } ;
277+
278+ contractGetOperatorFeeMock . mockRejectedValueOnce ( new Error ( 'revert' ) ) ;
279+
280+ const flow = new MockOracleLayer1GasFeeFlow ( false ) ;
281+ const response = await flow . getLayer1Fee ( request ) ;
282+
283+ expect ( contractGetOperatorFeeMock ) . toHaveBeenCalledTimes ( 1 ) ;
284+ expect ( response ) . toStrictEqual ( {
285+ layer1Fee : LAYER_1_FEE_MOCK ,
286+ } ) ;
287+ } ) ;
288+
289+ it ( 'defaults operator fee to zero when call returns undefined' , async ( ) => {
290+ const gasUsed = '0x2' ;
291+ request = {
292+ ...request ,
293+ transactionMeta : {
294+ ...request . transactionMeta ,
295+ gasUsed,
296+ } ,
297+ } ;
298+
299+ contractGetOperatorFeeMock . mockResolvedValueOnce (
300+ undefined as unknown as BN ,
301+ ) ;
302+
303+ const flow = new MockOracleLayer1GasFeeFlow ( false ) ;
304+ const response = await flow . getLayer1Fee ( request ) ;
305+
306+ expect ( contractGetOperatorFeeMock ) . toHaveBeenCalledTimes ( 1 ) ;
307+ expect ( response ) . toStrictEqual ( {
308+ layer1Fee : LAYER_1_FEE_MOCK ,
309+ } ) ;
310+ } ) ;
231311 } ) ;
232312} ) ;
0 commit comments