Skip to content

Commit f9cd1aa

Browse files
yahgwaigodzillabagzeoneth
authored
v2.1.3 (#291)
* set decimals in postUpgradeInit * more intentional function name * comment * call it postUpgradeInit * add zero check * Apply 7702 patch * Updated slither * Linting * Storage formatting changes * Added post upgrade init signature * Added post upgrade init sig * chore: v2.1.3 --------- Co-authored-by: Henry <[email protected]> Co-authored-by: gzeon <[email protected]> Co-authored-by: gzeon <[email protected]>
1 parent f843905 commit f9cd1aa

File tree

11 files changed

+64
-15
lines changed

11 files changed

+64
-15
lines changed

audit-ci.jsonc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
6565
// Server-Side Request Forgery in axios
6666
"GHSA-8hc4-vh64-cxmj",
6767
// Regular Expression Denial of Service (ReDoS) in micromatch
68-
"GHSA-952p-6rrq-rcjv"
68+
"GHSA-952p-6rrq-rcjv",
69+
// cookie accepts cookie name, path, and domain with out of bounds characters
70+
"GHSA-pxg6-pf52-xh8x"
6971
]
7072
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@arbitrum/nitro-contracts",
3-
"version": "2.1.2",
3+
"version": "2.1.3",
44
"description": "Layer 2 precompiles and rollup for Arbitrum Nitro",
55
"author": "Offchain Labs, Inc.",
66
"license": "BUSL-1.1",

slither.db.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/bridge/AbsInbox.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ import {
1111
InsufficientSubmissionCost,
1212
L1Forked,
1313
NotAllowedOrigin,
14-
NotOrigin,
14+
NotCodelessOrigin,
1515
NotRollupOrOwner,
1616
RetryableData
1717
} from "../libraries/Error.sol";
1818
import "./IInboxBase.sol";
1919
import "./ISequencerInbox.sol";
2020
import "./IBridge.sol";
2121
import "../libraries/AddressAliasHelper.sol";
22+
import "../libraries/CallerChecker.sol";
2223
import "../libraries/DelegateCallAware.sol";
2324
import {
2425
L1MessageType_submitRetryableTx,
@@ -138,8 +139,7 @@ abstract contract AbsInbox is DelegateCallAware, PausableUpgradeable, IInboxBase
138139
returns (uint256)
139140
{
140141
if (_chainIdChanged()) revert L1Forked();
141-
// solhint-disable-next-line avoid-tx-origin
142-
if (msg.sender != tx.origin) revert NotOrigin();
142+
if (!CallerChecker.isCallerCodelessOrigin()) revert NotCodelessOrigin();
143143
if (messageData.length > maxDataSize) revert DataTooLarge(messageData.length, maxDataSize);
144144
uint256 msgNum = _deliverToBridge(L2_MSG, msg.sender, keccak256(messageData), 0);
145145
emit InboxMessageDeliveredFromOrigin(msgNum);

src/bridge/Inbox.sol

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ contract Inbox is AbsInbox, IInbox {
118118
if (!_chainIdChanged()) revert NotForked();
119119
// solhint-disable-next-line avoid-tx-origin
120120
if (msg.sender != tx.origin) revert NotOrigin();
121+
// no code size check required because we only want to know if msg.sender is an EOA to undo alias
121122
// arbos will discard unsigned tx with gas limit too large
122123
if (gasLimit > type(uint64).max) {
123124
revert GasLimitTooLarge();
@@ -152,6 +153,7 @@ contract Inbox is AbsInbox, IInbox {
152153
if (!_chainIdChanged()) revert NotForked();
153154
// solhint-disable-next-line avoid-tx-origin
154155
if (msg.sender != tx.origin) revert NotOrigin();
156+
// no code size check required because we only want to know if msg.sender is an EOA to undo alias
155157
// arbos will discard unsigned tx with gas limit too large
156158
if (gasLimit > type(uint64).max) {
157159
revert GasLimitTooLarge();
@@ -185,6 +187,7 @@ contract Inbox is AbsInbox, IInbox {
185187
if (!_chainIdChanged()) revert NotForked();
186188
// solhint-disable-next-line avoid-tx-origin
187189
if (msg.sender != tx.origin) revert NotOrigin();
190+
// no code size check required because we only want to know if msg.sender is an EOA to undo alias
188191
// arbos will discard unsigned tx with gas limit too large
189192
if (gasLimit > type(uint64).max) {
190193
revert GasLimitTooLarge();

src/bridge/SequencerInbox.sol

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
NoSuchKeyset,
2222
NotForked,
2323
NotBatchPosterManager,
24+
NotCodelessOrigin,
2425
RollupNotChanged,
2526
DataBlobsNotSupported,
2627
InitParamZero,
@@ -38,6 +39,7 @@ import "../rollup/IRollupLogic.sol";
3839
import "./Messages.sol";
3940
import "../precompiles/ArbGasInfo.sol";
4041
import "../precompiles/ArbSys.sol";
42+
import "../libraries/CallerChecker.sol";
4143
import "../libraries/IReader4844.sol";
4244

4345
import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol";
@@ -360,8 +362,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
360362
uint256 prevMessageCount,
361363
uint256 newMessageCount
362364
) external refundsGas(gasRefunder, IReader4844(address(0))) {
363-
// solhint-disable-next-line avoid-tx-origin
364-
if (msg.sender != tx.origin) revert NotOrigin();
365+
if (!CallerChecker.isCallerCodelessOrigin()) revert NotCodelessOrigin();
365366
if (!isBatchPoster[msg.sender]) revert NotBatchPoster();
366367
(bytes32 dataHash, IBridge.TimeBounds memory timeBounds) = formCallDataHash(
367368
data,
@@ -457,10 +458,9 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
457458
if (hostChainIsArbitrum) revert DataBlobsNotSupported();
458459

459460
// submit a batch spending report to refund the entity that produced the blob batch data
460-
// same as using calldata, we only submit spending report if the caller is the origin of the tx
461+
// same as using calldata, we only submit spending report if the caller is the origin and is codeless
461462
// such that one cannot "double-claim" batch posting refund in the same tx
462-
// solhint-disable-next-line avoid-tx-origin
463-
if (msg.sender == tx.origin && !isUsingFeeToken) {
463+
if (CallerChecker.isCallerCodelessOrigin() && !isUsingFeeToken) {
464464
submitBatchSpendingReport(dataHash, seqMessageIndex, block.basefee, blobGas);
465465
}
466466
}

src/libraries/CallerChecker.sol

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2021-2024, Offchain Labs, Inc.
2+
// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE
3+
// SPDX-License-Identifier: BUSL-1.1
4+
5+
pragma solidity ^0.8.0;
6+
7+
library CallerChecker {
8+
/**
9+
* @notice A EIP-7702 safe check to ensure the caller is the origin and is codeless
10+
* @return bool true if the caller is the origin and is codeless, false otherwise
11+
* @dev If the caller is the origin and is codeless, then msg.data is guaranteed to be same as tx.data
12+
* It also mean the caller would not be able to call a contract multiple times with the same transaction
13+
*/
14+
function isCallerCodelessOrigin() internal view returns (bool) {
15+
// solhint-disable-next-line avoid-tx-origin
16+
return msg.sender == tx.origin && msg.sender.code.length == 0;
17+
}
18+
}

src/libraries/Error.sol

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ error HadZeroInit();
1313
/// @dev Thrown when post upgrade init validation fails
1414
error BadPostUpgradeInit();
1515

16+
/// @dev Thrown when the caller is not a codeless origin
17+
error NotCodelessOrigin();
18+
1619
/// @dev Thrown when non owner tries to access an only-owner function
1720
/// @param sender The msg.sender who is not the owner
1821
/// @param owner The owner address

src/libraries/GasRefundEnabled.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pragma solidity ^0.8.0;
77

88
import "./IReader4844.sol";
99
import "./IGasRefunder.sol";
10+
import "../libraries/CallerChecker.sol";
1011

1112
abstract contract GasRefundEnabled {
1213
uint256 internal immutable gasPerBlob = 2**17;
@@ -24,8 +25,7 @@ abstract contract GasRefundEnabled {
2425
startGasLeft += calldataWords * 6 + (calldataWords**2) / 512;
2526
// if triggered in a contract call, the spender may be overrefunded by appending dummy data to the call
2627
// so we check if it is a top level call, which would mean the sender paid calldata as part of tx.input
27-
// solhint-disable-next-line avoid-tx-origin
28-
if (msg.sender != tx.origin) {
28+
if (!CallerChecker.isCallerCodelessOrigin()) {
2929
// We can't be sure if this calldata came from the top level tx,
3030
// so to be safe we tell the gas refunder there was no calldata.
3131
calldataSize = 0;

test/foundry/AbsInbox.t.sol

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,10 +230,19 @@ abstract contract AbsInboxTest is Test {
230230
}
231231

232232
function test_sendL2MessageFromOrigin_revert_NotOrigin() public {
233-
vm.expectRevert(abi.encodeWithSelector(NotOrigin.selector));
233+
vm.expectRevert(abi.encodeWithSelector(NotCodelessOrigin.selector));
234234
inbox.sendL2MessageFromOrigin(abi.encodePacked("some msg"));
235235
}
236236

237+
function test_sendL2MessageFromOrigin_revert_NotCodeless() public {
238+
assertEq(user.code.length, 0, "user is codeless");
239+
vm.etch(user, bytes("some code"));
240+
vm.prank(user, user);
241+
vm.expectRevert(abi.encodeWithSelector(NotCodelessOrigin.selector));
242+
inbox.sendL2MessageFromOrigin(abi.encodePacked("some msg"));
243+
vm.etch(user, bytes(""));
244+
}
245+
237246
function test_sendL2Message() public {
238247
// L2 msg params
239248
bytes memory data = abi.encodePacked("some msg");

0 commit comments

Comments
 (0)