CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-eth-optimism--contracts

Smart contracts for Optimism Layer 2 scaling solution including L1/L2 messaging, bridging, rollup management, and predeploy contracts

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

standards-interfaces.mddocs/

Standards & Interfaces

Standard contracts and interfaces that define common patterns and APIs used throughout the Optimism ecosystem, including ERC20 tokens, cross-domain messaging interfaces, and address aliasing utilities.

L2StandardERC20

Contract Path: standards/L2StandardERC20.sol

Standard ERC20 implementation for L2 tokens with mint/burn capabilities for bridge integration.

Constructor

constructor(
  address _l2Bridge,
  address _l1Token,
  string memory _name,
  string memory _symbol
);

Parameters:

  • _l2Bridge (address): L2 bridge contract address that can mint/burn
  • _l1Token (address): Corresponding L1 token address
  • _name (string): Token name
  • _symbol (string): Token symbol

Key Functions

contract L2StandardERC20 {
  // Standard ERC20 functions
  function name() external view returns (string memory);
  function symbol() external view returns (string memory);
  function decimals() external view returns (uint8);
  function totalSupply() external view returns (uint256);
  function balanceOf(address account) external view returns (uint256);
  function transfer(address to, uint256 amount) external returns (bool);
  function allowance(address owner, address spender) external view returns (uint256);
  function approve(address spender, uint256 amount) external returns (bool);
  function transferFrom(address from, address to, uint256 amount) external returns (bool);
  
  // Bridge integration functions
  function mint(address _to, uint256 _amount) external;
  function burn(address _from, uint256 _amount) external;
  
  // Metadata functions
  function l1Token() external view returns (address);
  function l2Bridge() external view returns (address);
  
  // ERC165 support
  function supportsInterface(bytes4 _interfaceId) external view returns (bool);
}

mint

Mints tokens to an address (bridge only).

Parameters:

  • _to (address): Address to mint tokens to
  • _amount (uint256): Amount of tokens to mint

Restrictions: Only callable by the L2 bridge contract

burn

Burns tokens from an address (bridge only).

Parameters:

  • _from (address): Address to burn tokens from
  • _amount (uint256): Amount of tokens to burn

Restrictions: Only callable by the L2 bridge contract

l1Token

Returns the address of the corresponding L1 token.

Returns: address - L1 token contract address

l2Bridge

Returns the address of the L2 bridge contract.

Returns: address - L2 bridge contract address

Events

// Standard ERC20 events
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);

// Bridge-specific events
event Mint(address indexed _account, uint256 _amount);
event Burn(address indexed _account, uint256 _amount);

Usage Example

// Deploy L2 token for bridging
L2StandardERC20 l2Token = new L2StandardERC20(
  l2BridgeAddress,
  l1TokenAddress,
  "Optimism USD Coin",
  "USDC"
);

// Bridge will mint tokens when deposits arrive from L1
// Bridge will burn tokens when withdrawing to L1

AddressAliasHelper

Contract Path: standards/AddressAliasHelper.sol

Utilities for L1↔L2 address aliasing to prevent cross-domain replay attacks and ensure secure cross-layer communication.

Key Functions

library AddressAliasHelper {
  function applyL1ToL2Alias(address l1Address) 
    internal 
    pure 
    returns (address l2Address);
    
  function undoL1ToL2Alias(address l2Address) 
    internal 
    pure 
    returns (address l1Address);
}

applyL1ToL2Alias

Applies address aliasing for L1→L2 messages to prevent replay attacks.

Parameters:

  • l1Address (address): Original L1 address

Returns: address - Aliased L2 address

Usage:

// When an L1 contract sends a message, its address is aliased on L2
address l1Sender = 0x1234567890123456789012345678901234567890;
address aliasedSender = AddressAliasHelper.applyL1ToL2Alias(l1Sender);

// L2 contracts should check for the aliased address
require(msg.sender == aliasedSender, "Invalid L1 sender");

undoL1ToL2Alias

Removes address aliasing to recover the original L1 address.

Parameters:

  • l2Address (address): Aliased L2 address

Returns: address - Original L1 address

Usage:

// Recover original L1 address from aliased L2 address
address originalL1 = AddressAliasHelper.undoL1ToL2Alias(msg.sender);

Aliasing Rules

The address aliasing uses a constant offset to transform addresses:

  • L1→L2 Aliasing: l2Address = l1Address + 0x1111000000000000000000000000000000001111
  • L2→L1 Recovery: l1Address = l2Address - 0x1111000000000000000000000000000000001111

Core Interfaces

ICrossDomainMessenger

Contract Path: libraries/bridge/ICrossDomainMessenger.sol

Base interface for cross-domain messenger contracts (both L1 and L2).

interface ICrossDomainMessenger {
  function sendMessage(
    address _target,
    bytes calldata _message,
    uint32 _gasLimit
  ) external;
  
  function xDomainMessageSender() external view returns (address);
}

sendMessage

Sends a message to the other domain.

Parameters:

  • _target (address): Target contract address on the other domain
  • _message (bytes): Message data to send
  • _gasLimit (uint32): Gas limit for execution on the other domain

xDomainMessageSender

Returns the sender address from the other domain when processing a cross-domain message.

Returns: address - Cross-domain sender address

IL1CrossDomainMessenger

Contract Path: L1/messaging/IL1CrossDomainMessenger.sol

Interface for L1 cross-domain messenger functionality.

interface IL1CrossDomainMessenger is ICrossDomainMessenger {
  function relayMessage(
    address _target,
    address _sender,
    bytes memory _message,
    uint256 _messageNonce,
    L2MessageInclusionProof memory _proof
  ) external;
  
  function replayMessage(
    address _target,
    address _sender,
    bytes memory _message,
    uint256 _queueIndex,
    uint32 _oldGasLimit,
    uint32 _newGasLimit
  ) external;
}

IL2CrossDomainMessenger

Contract Path: L2/messaging/IL2CrossDomainMessenger.sol

Interface for L2 cross-domain messenger functionality.

interface IL2CrossDomainMessenger is ICrossDomainMessenger {
  function relayMessage(
    address _target,
    address _sender,
    bytes memory _message,
    uint256 _messageNonce
  ) external;
}

IL1StandardBridge

Contract Path: L1/messaging/IL1StandardBridge.sol

Interface for L1 standard bridge functionality.

interface IL1StandardBridge {
  function depositETH(uint32 _l2Gas, bytes calldata _data) external payable;
  
  function depositETHTo(
    address _to,
    uint32 _l2Gas,
    bytes calldata _data
  ) external payable;
  
  function depositERC20(
    address _l1Token,
    address _l2Token,
    uint256 _amount,
    uint32 _l2Gas,
    bytes calldata _data
  ) external;
  
  function finalizeETHWithdrawal(
    address _from,
    address _to,
    uint256 _amount,
    bytes calldata _data
  ) external;
  
  function finalizeERC20Withdrawal(
    address _l1Token,
    address _l2Token,
    address _from,
    address _to,
    uint256 _amount,
    bytes calldata _data
  ) external;
}

IL2ERC20Bridge

Contract Path: L2/messaging/IL2ERC20Bridge.sol

Interface for L2 bridge functionality.

interface IL2ERC20Bridge {
  function withdraw(
    address _l2Token,
    uint256 _amount,
    uint32 _l1Gas,
    bytes calldata _data
  ) external;
  
  function withdrawTo(
    address _l2Token,
    address _to,
    uint256 _amount,
    uint32 _l1Gas,
    bytes calldata _data
  ) external;
  
  function finalizeDeposit(
    address _l1Token,
    address _l2Token,
    address _from,
    address _to,
    uint256 _amount,
    bytes calldata _data
  ) external;
}

IL2StandardERC20

Contract Path: standards/IL2StandardERC20.sol

Interface for L2 standard ERC20 tokens with mint/burn capabilities.

interface IL2StandardERC20 {
  function mint(address _to, uint256 _amount) external;
  function burn(address _from, uint256 _amount) external;
  
  function l1Token() external returns (address);
  
  // Standard ERC20 functions
  function name() external view returns (string memory);
  function symbol() external view returns (string memory);
  function decimals() external view returns (uint8);
  function totalSupply() external view returns (uint256);
  function balanceOf(address account) external view returns (uint256);
  function transfer(address to, uint256 amount) external returns (bool);
  function allowance(address owner, address spender) external view returns (uint256);
  function approve(address spender, uint256 amount) external returns (bool);
  function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

Common Patterns and Usage

Cross-Domain Message Authentication

contract SecureCrossDomainReceiver {
  ICrossDomainMessenger public messenger;
  address public trustedRemoteSender;
  
  modifier onlyFromTrustedRemote() {
    require(
      msg.sender == address(messenger) &&
      messenger.xDomainMessageSender() == trustedRemoteSender,
      "Unauthorized cross-domain call"
    );
    _;
  }
  
  function handleRemoteCall(bytes calldata data) 
    external 
    onlyFromTrustedRemote 
  {
    // Process trusted cross-domain message
  }
}

L1 Contract Aliasing Check

contract L2ContractReceiver {
  using AddressAliasHelper for address;
  
  address public trustedL1Contract;
  
  function handleL1Message(bytes calldata data) external {
    // Check if sender is the aliased L1 contract
    address expectedAlias = trustedL1Contract.applyL1ToL2Alias();
    require(msg.sender == expectedAlias, "Invalid L1 sender");
    
    // Process message from trusted L1 contract
  }
}

Standard L2 Token Implementation

contract MyL2Token is L2StandardERC20 {
  constructor(
    address _l2Bridge,
    address _l1Token,
    string memory _name,
    string memory _symbol
  ) L2StandardERC20(_l2Bridge, _l1Token, _name, _symbol) {
    // Additional initialization if needed
  }
  
  // Tokens are automatically mintable/burnable by the bridge
  // Standard ERC20 functionality is inherited
}

Bridge Integration Example

contract BridgeIntegration {
  IL1StandardBridge public l1Bridge;
  IL2ERC20Bridge public l2Bridge;
  
  function bridgeTokensToL2(
    address l1Token,
    address l2Token,
    uint256 amount
  ) external {
    // Approve bridge to spend tokens
    IERC20(l1Token).approve(address(l1Bridge), amount);
    
    // Deposit tokens to L2
    l1Bridge.depositERC20(
      l1Token,
      l2Token,
      amount,
      200000, // L2 gas limit
      ""
    );
  }
  
  function bridgeTokensToL1(
    address l2Token,
    uint256 amount
  ) external {
    // Withdraw tokens to L1
    l2Bridge.withdraw(
      l2Token,
      amount,
      200000, // L1 gas limit
      ""
    );
  }
}

Complete Cross-Domain Application

// L1 Contract
contract L1Controller {
  IL1CrossDomainMessenger public messenger;
  address public l2Controller;
  
  function sendCommandToL2(uint256 command, bytes calldata data) external {
    bytes memory message = abi.encodeWithSignature(
      "executeCommand(uint256,bytes)",
      command,
      data
    );
    
    messenger.sendMessage(l2Controller, message, 200000);
  }
  
  function handleL2Response(uint256 result) external {
    require(
      msg.sender == address(messenger) &&
      messenger.xDomainMessageSender() == l2Controller,
      "Invalid L2 response"
    );
    
    // Process result from L2
  }
}

// L2 Contract
contract L2Controller {
  using AddressAliasHelper for address;
  
  IL2CrossDomainMessenger public messenger;
  address public l1Controller;
  
  function executeCommand(uint256 command, bytes calldata data) external {
    // Verify sender is aliased L1 controller
    require(
      msg.sender == l1Controller.applyL1ToL2Alias(),
      "Invalid L1 sender"
    );
    
    // Execute command
    uint256 result = processCommand(command, data);
    
    // Send response back to L1
    bytes memory response = abi.encodeWithSignature(
      "handleL2Response(uint256)",
      result
    );
    
    messenger.sendMessage(l1Controller, response, 200000);
  }
  
  function processCommand(uint256 command, bytes calldata data) 
    internal 
    returns (uint256) 
  {
    // Command processing logic
    return 42;
  }
}

This standards and interfaces documentation provides the foundation for building secure, interoperable contracts within the Optimism ecosystem, with proper cross-domain authentication and standard token implementations.

docs

index.md

l1-messaging-bridging.md

l1-rollup-management.md

l2-messaging-bridging.md

l2-system-contracts.md

standards-interfaces.md

typescript-utilities.md

utility-libraries.md

tile.json