Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Customization

Table of Contents

Custom gas tokens

We present PoCs for custom gas token implementations using Linea's messaging bridge as inspiration, which is reported here:

  /**
   * @notice Adds a message for sending cross-chain and emits MessageSent.
   * @dev The message number is preset (nextMessageNumber) and only incremented at the end if successful for the next caller.
   * @dev This function should be called with a msg.value = _value + _fee. The fee will be paid on the destination chain.
   * @param _to The address the message is intended for.
   * @param _fee The fee being paid for the message delivery.
   * @param _calldata The calldata to pass to the recipient.
   */
  function sendMessage(
    address _to,
    uint256 _fee,
    bytes calldata _calldata
  ) external payable whenTypeAndGeneralNotPaused(PauseType.L1_L2) {
    if (_to == address(0)) {
      revert ZeroAddressNotAllowed();
    }

    if (_fee > msg.value) {
      revert ValueSentTooLow();
    }

    uint256 messageNumber = nextMessageNumber++;
    uint256 valueSent = msg.value - _fee;

    bytes32 messageHash = MessageHashing._hashMessage(msg.sender, _to, _fee, valueSent, messageNumber, _calldata);

    _addRollingHash(messageNumber, messageHash);

    emit MessageSent(msg.sender, _to, _fee, valueSent, messageNumber, _calldata, messageHash);
  }

Arbitrary ERC20

Instead of using msg.value as the valueSent, we use ERC20 transfer amount.

function sendMessage(
  address _to,
  uint256 _fee,
  uint256 _value,
  bytes calldata _calldata
) external whenTypeAndGeneralNotPaused(PauseType.L1_L2) {
  if (_to == address(0)) {
    revert ZeroAddressNotAllowed();
  }

  uint256 totalAmount = _value + _fee;

  bool success = gasToken.transferFrom(msg.sender, address(this), totalAmount);
  if (!success) {
    revert TokenTransferFailed();
  }

  uint256 messageNumber = nextMessageNumber++;

  bytes32 messageHash = MessageHashing._hashMessage(
    msg.sender,
    _to,
    _fee,
    _value,
    messageNumber,
    _calldata
  );

  _addRollingHash(messageNumber, messageHash);

  emit MessageSent(msg.sender, _to, _fee, _value, messageNumber, _calldata, messageHash);
}

Special considerations apply when tokens with non-standard decimals or transfer logic are used.

ETH burn

Instead of collecting deposits, the ETH sent is burned to a designated burn address.

function sendMessage(
  address _to,
  uint256 _fee,
  bytes calldata _calldata
) external payable whenTypeAndGeneralNotPaused(PauseType.L1_L2) {
  if (_to == address(0)) {
    revert ZeroAddressNotAllowed();
  }

  if (_fee > msg.value) {
    revert ValueSentTooLow();
  }

  uint256 messageNumber = nextMessageNumber++;
  uint256 valueSent = msg.value - _fee;

  // Burn the full amount
  (bool success, ) = address(BURN_ADDRESS).call{value: msg.value}("");
  if (!success) {
    revert BurnFailed();
  }

  bytes32 messageHash = MessageHashing._hashMessage(msg.sender, _to, _fee, valueSent, messageNumber, _calldata);

  _addRollingHash(messageNumber, messageHash);

  emit MessageSent(msg.sender, _to, _fee, valueSent, messageNumber, _calldata, messageHash);
}

NFT-gated gas credits

NFT holders can claim free gas tokens on L2 once per NFT.

function sendMessage(
  address _to,
  uint256 _tokenId,
  bytes calldata _calldata
) external whenTypeAndGeneralNotPaused(PauseType.L1_L2) {
  if (_to == address(0)) {
    revert ZeroAddressNotAllowed();
  }

  if (NFT_COLLECTION.ownerOf(_tokenId) != msg.sender) {
    revert NotNFTOwner();
  }

  if (claimed[_tokenId]) {
    revert AlreadyClaimed();
  }

  claimed[_tokenId] = true;

  uint256 messageNumber = nextMessageNumber++;
  uint256 valueSent = GAS_CREDIT_AMOUNT;

  bytes32 messageHash = MessageHashing._hashMessage(msg.sender, _to, 0, valueSent, messageNumber, _calldata);

  _addRollingHash(messageNumber, messageHash);

  emit MessageSent(msg.sender, _to, 0, valueSent, messageNumber, _calldata, messageHash);
}

Custom sequencing

TODO

Custom VMs

TODO