Skip to content

feat: add contracts for alternative gas token design #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ libs = ["lib"]
remappings = [] # a list of remappings
libraries = [] # a list of deployed libraries to link against
cache = true # whether to cache builds or not
force = true # whether to ignore the cache (clean build)
# evm_version = 'london' # the evm version (by hardfork name)
force = false # whether to ignore the cache (clean build)
evm_version = 'cancun' # the evm version (by hardfork name)
solc_version = '0.8.24' # override for the solc version (setting this ignores `auto_detect_solc`)
optimizer = true # enable or disable the solc optimizer
optimizer_runs = 200 # the number of optimizer runs
Expand Down
172 changes: 98 additions & 74 deletions src/L1/L1ScrollMessenger.sol
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
address _feeVault,
address _rollup,
address _messageQueue
) public initializer {
) external initializer {
ScrollMessengerBase.__ScrollMessengerBase_init(_counterpart, _feeVault);

__rollup = _rollup;
Expand Down Expand Up @@ -162,36 +162,7 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
bytes memory _message,
L2MessageProof memory _proof
) external override whenNotPaused notInExecution {
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(_from, _to, _value, _nonce, _message));
require(!isL2MessageExecuted[_xDomainCalldataHash], "Message was already successfully executed");

{
require(IScrollChain(rollup).isBatchFinalized(_proof.batchIndex), "Batch is not finalized");
bytes32 _messageRoot = IScrollChain(rollup).withdrawRoots(_proof.batchIndex);
require(
WithdrawTrieVerifier.verifyMerkleProof(_messageRoot, _xDomainCalldataHash, _nonce, _proof.merkleProof),
"Invalid proof"
);
}

// @note check more `_to` address to avoid attack in the future when we add more gateways.
require(_to != messageQueue, "Forbid to call message queue");
_validateTargetAddress(_to);

// @note This usually will never happen, just in case.
require(_from != xDomainMessageSender, "Invalid message sender");

xDomainMessageSender = _from;
(bool success, ) = _to.call{value: _value}(_message);
// reset value to refund gas.
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;

if (success) {
isL2MessageExecuted[_xDomainCalldataHash] = true;
emit RelayedMessage(_xDomainCalldataHash);
} else {
emit FailedRelayedMessage(_xDomainCalldataHash);
}
_relayMessageWithProof(_from, _to, _value, _nonce, _message, _proof);
}

/// @inheritdoc IL1ScrollMessenger
Expand Down Expand Up @@ -266,48 +237,7 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
uint256 _messageNonce,
bytes memory _message
) external override whenNotPaused notInExecution {
// The criteria for dropping a message:
// 1. The message is a L1 message.
// 2. The message has not been dropped before.
// 3. the message and all of its replacement are finalized in L1.
// 4. the message and all of its replacement are skipped.
//
// Possible denial of service attack:
// + replayMessage is called every time someone want to drop the message.
// + replayMessage is called so many times for a skipped message, thus results a long list.
//
// We limit the number of `replayMessage` calls of each message, which may solve the above problem.

// check message exists
bytes memory _xDomainCalldata = _encodeXDomainCalldata(_from, _to, _value, _messageNonce, _message);
bytes32 _xDomainCalldataHash = keccak256(_xDomainCalldata);
require(messageSendTimestamp[_xDomainCalldataHash] > 0, "Provided message has not been enqueued");

// check message not dropped
require(!isL1MessageDropped[_xDomainCalldataHash], "Message already dropped");

// check message is finalized
uint256 _lastIndex = replayStates[_xDomainCalldataHash].lastIndex;
if (_lastIndex == 0) _lastIndex = _messageNonce;

// check message is skipped and drop it.
// @note If the list is very long, the message may never be dropped.
while (true) {
IL1MessageQueue(messageQueue).dropCrossDomainMessage(_lastIndex);
_lastIndex = prevReplayIndex[_lastIndex];
if (_lastIndex == 0) break;
unchecked {
_lastIndex = _lastIndex - 1;
}
}

isL1MessageDropped[_xDomainCalldataHash] = true;

// set execution context
xDomainMessageSender = ScrollConstants.DROP_XDOMAIN_MESSAGE_SENDER;
IMessageDropCallback(_from).onDropMessage{value: _value}(_message);
// clear execution context
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;
_dropMessage(_from, _to, _value, _messageNonce, _message);
}

/************************
Expand All @@ -328,13 +258,14 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
* Internal Functions *
**********************/

/// @dev Internal function to do `sendMessage` function call.
function _sendMessage(
address _to,
uint256 _value,
bytes memory _message,
uint256 _gasLimit,
address _refundAddress
) internal nonReentrant {
) internal virtual nonReentrant {
// compute the actual cross domain message calldata.
uint256 _messageNonce = IL1MessageQueue(messageQueue).nextCrossDomainMessageIndex();
bytes memory _xDomainCalldata = _encodeXDomainCalldata(_msgSender(), _to, _value, _messageNonce, _message);
Expand Down Expand Up @@ -368,4 +299,97 @@ contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
}
}
}

/// @dev Internal function to do `relayMessageWithProof` function call.
function _relayMessageWithProof(
address _from,
address _to,
uint256 _value,
uint256 _nonce,
bytes memory _message,
L2MessageProof memory _proof
) internal virtual {
bytes32 _xDomainCalldataHash = keccak256(_encodeXDomainCalldata(_from, _to, _value, _nonce, _message));
require(!isL2MessageExecuted[_xDomainCalldataHash], "Message was already successfully executed");

{
require(IScrollChain(rollup).isBatchFinalized(_proof.batchIndex), "Batch is not finalized");
bytes32 _messageRoot = IScrollChain(rollup).withdrawRoots(_proof.batchIndex);
require(
WithdrawTrieVerifier.verifyMerkleProof(_messageRoot, _xDomainCalldataHash, _nonce, _proof.merkleProof),
"Invalid proof"
);
}

// @note check more `_to` address to avoid attack in the future when we add more gateways.
require(_to != messageQueue, "Forbid to call message queue");
_validateTargetAddress(_to);

// @note This usually will never happen, just in case.
require(_from != xDomainMessageSender, "Invalid message sender");

xDomainMessageSender = _from;
(bool success, ) = _to.call{value: _value}(_message);
// reset value to refund gas.
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;

if (success) {
isL2MessageExecuted[_xDomainCalldataHash] = true;
emit RelayedMessage(_xDomainCalldataHash);
} else {
emit FailedRelayedMessage(_xDomainCalldataHash);
}
}

/// @dev Internal function to do `dropMessage` function call.
function _dropMessage(
address _from,
address _to,
uint256 _value,
uint256 _messageNonce,
bytes memory _message
) internal virtual {
// The criteria for dropping a message:
// 1. The message is a L1 message.
// 2. The message has not been dropped before.
// 3. the message and all of its replacement are finalized in L1.
// 4. the message and all of its replacement are skipped.
//
// Possible denial of service attack:
// + replayMessage is called every time someone want to drop the message.
// + replayMessage is called so many times for a skipped message, thus results a long list.
//
// We limit the number of `replayMessage` calls of each message, which may solve the above problem.

// check message exists
bytes memory _xDomainCalldata = _encodeXDomainCalldata(_from, _to, _value, _messageNonce, _message);
bytes32 _xDomainCalldataHash = keccak256(_xDomainCalldata);
require(messageSendTimestamp[_xDomainCalldataHash] > 0, "Provided message has not been enqueued");

// check message not dropped
require(!isL1MessageDropped[_xDomainCalldataHash], "Message already dropped");

// check message is finalized
uint256 _lastIndex = replayStates[_xDomainCalldataHash].lastIndex;
if (_lastIndex == 0) _lastIndex = _messageNonce;

// check message is skipped and drop it.
// @note If the list is very long, the message may never be dropped.
while (true) {
IL1MessageQueue(messageQueue).dropCrossDomainMessage(_lastIndex);
_lastIndex = prevReplayIndex[_lastIndex];
if (_lastIndex == 0) break;
unchecked {
_lastIndex = _lastIndex - 1;
}
}

isL1MessageDropped[_xDomainCalldataHash] = true;

// set execution context
xDomainMessageSender = ScrollConstants.DROP_XDOMAIN_MESSAGE_SENDER;
IMessageDropCallback(_from).onDropMessage{value: _value}(_message);
// clear execution context
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;
}
}
2 changes: 1 addition & 1 deletion src/L1/gateways/L1ETHGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// @title L1ETHGateway
/// @notice The `L1ETHGateway` is used to deposit ETH on layer 1 and
/// finalize withdraw ETH from layer 2.
/// @dev The deposited ETH tokens are held in this gateway. On finalizing withdraw, the corresponding
/// @dev The deposited ETH tokens are held in `L1ScrollMessenger`. On finalizing withdraw, the corresponding
/// ETH will be transfer to the recipient directly.
contract L1ETHGateway is ScrollGatewayBase, IL1ETHGateway, IMessageDropCallback {
/***************
Expand Down
Loading
Loading