Secure Smart Contract library providing battle-tested implementations of industry-standard Solidity contracts including ERC20, ERC721, ERC1155 tokens, access control mechanisms, proxy patterns, and governance systems for Ethereum and EVM-compatible blockchains.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
OpenZeppelin Contracts provides cross-chain messaging utilities that enable smart contracts to communicate across different blockchain networks, supporting various Layer 2 solutions and bridges.
Import cross-chain contracts using Solidity import statements:
import "@openzeppelin/contracts/crosschain/CrossChainEnabled.sol";
import "@openzeppelin/contracts/crosschain/optimism/CrossChainEnabledOptimism.sol";
import "@openzeppelin/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol";
import "@openzeppelin/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol";
import "@openzeppelin/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol";
import "@openzeppelin/contracts/crosschain/amb/CrossChainEnabledAMB.sol";Core abstraction for cross-chain message handling that provides a unified interface across different bridge implementations.
abstract contract CrossChainEnabled {
function _isCrossChain() internal view virtual returns (bool);
function _crossChainSender() internal view virtual returns (address);
}Errors:
NotCrossChainCall() - Called when function is not executed from cross-chain contextInvalidCrossChainSender(address actual, address expected) - Invalid cross-chain message senderModifiers:
onlyCrossChain() - Restricts function to cross-chain calls onlyonlyCrossChainSender(address expected) - Restricts to specific cross-chain senderCross-chain messaging integration for Optimism Layer 2 network using the Optimism bridge.
abstract contract CrossChainEnabledOptimism is CrossChainEnabled {
constructor(address crossChainMessenger);
function crossChainMessenger() public view virtual returns (address);
}Usage Example:
contract OptimismContract is CrossChainEnabledOptimism {
constructor() CrossChainEnabledOptimism(0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1) {}
function handleCrossChainMessage(uint256 data) external onlyCrossChain {
address sender = _crossChainSender();
// Process cross-chain message
}
}Cross-chain messaging for Arbitrum Layer 1 contracts that need to communicate with Arbitrum Layer 2.
abstract contract CrossChainEnabledArbitrumL1 is CrossChainEnabled {
constructor(address bridge);
function bridge() public view virtual returns (address);
}Cross-chain messaging for Arbitrum Layer 2 contracts communicating with Layer 1.
abstract contract CrossChainEnabledArbitrumL2 is CrossChainEnabled {
constructor(address arbSys);
function arbSys() public view virtual returns (address);
}Cross-chain integration for Polygon Proof-of-Stake bridge enabling communication between Ethereum mainnet and Polygon.
abstract contract CrossChainEnabledPolygonChild is CrossChainEnabled {
constructor(address fxChild);
function fxChild() public view virtual returns (address);
}Generic cross-chain messaging through Arbitrary Message Bridge protocol, supporting various bridge implementations.
abstract contract CrossChainEnabledAMB is CrossChainEnabled {
constructor(address bridge);
function bridge() public view virtual returns (address);
}Maintain synchronized state across multiple chains:
contract MultiChainRegistry is CrossChainEnabledOptimism {
mapping(bytes32 => address) public registry;
event CrossChainRegistryUpdate(bytes32 indexed key, address indexed value, address indexed sender);
function updateRegistry(bytes32 key, address value) external onlyCrossChain {
address sender = _crossChainSender();
registry[key] = value;
emit CrossChainRegistryUpdate(key, value, sender);
}
function localUpdate(bytes32 key, address value) external {
registry[key] = value;
// Trigger cross-chain update to other networks
}
}Implement access control that works across multiple chains:
contract CrossChainAccessControl is AccessControl, CrossChainEnabledOptimism {
bytes32 public constant CROSS_CHAIN_ADMIN = keccak256("CROSS_CHAIN_ADMIN");
modifier onlyCrossChainAdmin() {
require(
hasRole(CROSS_CHAIN_ADMIN, _msgSender()) ||
(_isCrossChain() && hasRole(CROSS_CHAIN_ADMIN, _crossChainSender())),
"Not cross-chain admin"
);
_;
}
function crossChainGrantRole(bytes32 role, address account) external onlyCrossChainAdmin {
_grantRole(role, account);
}
}Basic pattern for cross-chain token operations:
contract CrossChainToken is ERC20, CrossChainEnabledOptimism {
mapping(uint256 => bool) public processedMessages;
event CrossChainMint(address indexed to, uint256 amount, uint256 indexed messageId);
event CrossChainBurn(address indexed from, uint256 amount, uint256 indexed messageId);
function crossChainMint(address to, uint256 amount, uint256 messageId)
external
onlyCrossChain
{
require(!processedMessages[messageId], "Message already processed");
processedMessages[messageId] = true;
_mint(to, amount);
emit CrossChainMint(to, amount, messageId);
}
function crossChainBurn(uint256 amount, uint256 messageId) external {
_burn(msg.sender, amount);
emit CrossChainBurn(msg.sender, amount, messageId);
// Trigger cross-chain mint on destination
}
}Always validate cross-chain messages and their senders:
contract SecureCrossChain is CrossChainEnabledOptimism {
address public trustedL1Contract;
function processMessage(bytes calldata data) external onlyCrossChainSender(trustedL1Contract) {
// Process validated cross-chain message
}
}Implement nonces or message IDs to prevent replay attacks:
contract ReplayProtected is CrossChainEnabledOptimism {
mapping(uint256 => bool) public processedMessages;
uint256 public nextMessageId;
function processMessage(uint256 messageId, bytes calldata data) external onlyCrossChain {
require(!processedMessages[messageId], "Message replayed");
processedMessages[messageId] = true;
// Process message
}
}Install with Tessl CLI
npx tessl i tessl/npm-openzeppelin-solidity