@@ -23,6 +23,7 @@ import {
2323 NoSuchKeyset,
2424 NotForked,
2525 NotBatchPosterManager,
26+ RollupNotChanged,
2627 DataBlobsNotSupported,
2728 InitParamZero,
2829 MissingDataHashes,
@@ -31,6 +32,7 @@ import {
3132 RollupNotChanged,
3233 EmptyBatchData,
3334 InvalidHeaderFlag,
35+ NativeTokenMismatch,
3436 Deprecated
3537} from "../libraries/Error.sol " ;
3638import "./IBridge.sol " ;
@@ -47,6 +49,7 @@ import "../libraries/DelegateCallAware.sol";
4749import {IGasRefunder} from "../libraries/IGasRefunder.sol " ;
4850import {GasRefundEnabled} from "../libraries/GasRefundEnabled.sol " ;
4951import "../libraries/ArbitrumChecker.sol " ;
52+ import {IERC20Bridge } from "./IERC20Bridge.sol " ;
5053
5154/**
5255 * @title Accepts batches from the sequencer and adds them to the rollup inbox.
@@ -122,15 +125,22 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
122125 uint256 internal immutable deployTimeChainId = block .chainid ;
123126 // If the chain this SequencerInbox is deployed on is an Arbitrum chain.
124127 bool internal immutable hostChainIsArbitrum = ArbitrumChecker.runningOnArbitrum ();
125-
126- constructor (uint256 _maxDataSize , IReader4844 reader4844_ ) {
128+ // True if the chain this SequencerInbox is deployed on uses custom fee token
129+ bool public immutable isUsingFeeToken;
130+
131+ constructor (
132+ uint256 _maxDataSize ,
133+ IReader4844 reader4844_ ,
134+ bool _isUsingFeeToken
135+ ) {
127136 maxDataSize = _maxDataSize;
128137 if (hostChainIsArbitrum) {
129138 if (reader4844_ != IReader4844 (address (0 ))) revert DataBlobsNotSupported ();
130139 } else {
131140 if (reader4844_ == IReader4844 (address (0 ))) revert InitParamZero ("Reader4844 " );
132141 }
133142 reader4844 = reader4844_;
143+ isUsingFeeToken = _isUsingFeeToken;
134144 }
135145
136146 function _chainIdChanged () internal view returns (bool ) {
@@ -175,6 +185,19 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
175185 ) external onlyDelegated {
176186 if (bridge != IBridge (address (0 ))) revert AlreadyInit ();
177187 if (bridge_ == IBridge (address (0 ))) revert HadZeroInit ();
188+
189+ // Make sure logic contract was created by proper value for 'isUsingFeeToken'.
190+ // Bridge in ETH based chains doesn't implement nativeToken(). In future it might implement it and return address(0)
191+ bool actualIsUsingFeeToken = false ;
192+ try IERC20Bridge (address (bridge_)).nativeToken () returns (address feeToken ) {
193+ if (feeToken != address (0 )) {
194+ actualIsUsingFeeToken = true ;
195+ }
196+ } catch {}
197+ if (isUsingFeeToken != actualIsUsingFeeToken) {
198+ revert NativeTokenMismatch ();
199+ }
200+
178201 bridge = bridge_;
179202 rollup = bridge_.rollup ();
180203 delayBlocks = maxTimeVariation_.delayBlocks;
@@ -444,7 +467,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
444467 // same as using calldata, we only submit spending report if the caller is the origin of the tx
445468 // such that one cannot "double-claim" batch posting refund in the same tx
446469 // solhint-disable-next-line avoid-tx-origin
447- if (msg .sender == tx .origin ) {
470+ if (msg .sender == tx .origin && ! isUsingFeeToken ) {
448471 submitBatchSpendingReport (dataHash, seqMessageIndex, block .basefee , blobGas);
449472 }
450473 }
@@ -682,7 +705,8 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
682705
683706 totalDelayedMessagesRead = afterDelayedMessagesRead;
684707
685- if (calldataLengthPosted > 0 ) {
708+ if (calldataLengthPosted > 0 && ! isUsingFeeToken) {
709+ // only report batch poster spendings if chain is using ETH as native currency
686710 submitBatchSpendingReport (dataHash, seqMessageIndex, block .basefee , 0 );
687711 }
688712 }
0 commit comments