Source Code
Overview
ETH Balance
0.001 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 252 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Relay Messages T... | 6792276 | 107 days ago | IN | 0 ETH | 0.00950521 | ||||
Relay Messages T... | 6792276 | 107 days ago | IN | 0 ETH | 0.01175005 | ||||
Relay Messages T... | 6792263 | 107 days ago | IN | 0 ETH | 0.01160819 | ||||
Relay Messages T... | 6792243 | 107 days ago | IN | 0 ETH | 0.00841256 | ||||
Relay Messages T... | 6792233 | 107 days ago | IN | 0 ETH | 0.00834651 | ||||
Relay Messages T... | 6792229 | 107 days ago | IN | 0 ETH | 0.00888482 | ||||
Relay Messages T... | 6792182 | 107 days ago | IN | 0 ETH | 0.00762938 | ||||
Relay Messages T... | 6792175 | 107 days ago | IN | 0 ETH | 0.01089332 | ||||
Relay Messages T... | 6792161 | 107 days ago | IN | 0 ETH | 0.00861091 | ||||
Relay Messages T... | 6792161 | 107 days ago | IN | 0 ETH | 0.01067853 | ||||
Relay Messages T... | 6792152 | 107 days ago | IN | 0 ETH | 0.01045468 | ||||
Relay Messages T... | 6792131 | 107 days ago | IN | 0 ETH | 0.00739272 | ||||
Relay Messages T... | 6792131 | 107 days ago | IN | 0 ETH | 0.00916783 | ||||
Relay Messages T... | 6792114 | 107 days ago | IN | 0 ETH | 0.01092378 | ||||
Relay Messages T... | 6792091 | 107 days ago | IN | 0 ETH | 0.01286317 | ||||
Relay Messages T... | 6792081 | 107 days ago | IN | 0 ETH | 0.01454634 | ||||
Relay Messages T... | 6792067 | 107 days ago | IN | 0 ETH | 0.0183279 | ||||
Relay Messages T... | 6792054 | 107 days ago | IN | 0 ETH | 0.01417322 | ||||
Relay Messages T... | 6792043 | 107 days ago | IN | 0 ETH | 0.0089151 | ||||
Relay Messages T... | 6792029 | 107 days ago | IN | 0 ETH | 0.00777227 | ||||
Relay Messages T... | 6791961 | 107 days ago | IN | 0 ETH | 0.00759344 | ||||
Relay Messages T... | 6791947 | 107 days ago | IN | 0 ETH | 0.00992955 | ||||
Relay Messages T... | 6791936 | 107 days ago | IN | 0 ETH | 0.00743939 | ||||
Relay Messages T... | 6791927 | 107 days ago | IN | 0 ETH | 0.00557474 | ||||
Relay Messages T... | 6791838 | 107 days ago | IN | 0 ETH | 0.01067978 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Yaho
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 10000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { MessageIdCalculator } from "./utils/MessageIdCalculator.sol"; import { MessageHashCalculator } from "./utils/MessageHashCalculator.sol"; import { IYaho } from "./interfaces/IYaho.sol"; import { IReporter } from "./interfaces/IReporter.sol"; import { Message } from "./interfaces/IMessage.sol"; import { IAdapter } from "./interfaces/IAdapter.sol"; contract Yaho is IYaho, MessageIdCalculator, MessageHashCalculator { mapping(uint256 => bytes32) private _pendingMessageHashes; uint256 public currentNonce; /// @inheritdoc IYaho function dispatchMessage( uint256 targetChainId, uint256 threshold, address receiver, bytes calldata data, IReporter[] calldata reporters, IAdapter[] calldata adapters ) external returns (uint256) { _checkReportersAndAdapters(threshold, reporters, adapters); (uint256 messageId, bytes32 messageHash) = _dispatchMessage( targetChainId, threshold, receiver, data, reporters, adapters ); _pendingMessageHashes[messageId] = messageHash; return messageId; } /// @inheritdoc IYaho function dispatchMessageToAdapters( uint256 targetChainId, uint256 threshold, address receiver, bytes calldata data, IReporter[] calldata reporters, IAdapter[] calldata adapters ) external payable returns (uint256, bytes32[] memory) { _checkReportersAndAdapters(threshold, reporters, adapters); (uint256 messageId, bytes32 messageHash) = _dispatchMessage( targetChainId, threshold, receiver, data, reporters, adapters ); bytes32[] memory reportersReceipts = _dispatchMessageToAdapters( targetChainId, messageId, messageHash, reporters, adapters ); return (messageId, reportersReceipts); } /// @inheritdoc IYaho function dispatchMessagesToAdapters( uint256 targetChainId, uint256[] calldata thresholds, address[] calldata receivers, bytes[] calldata data, IReporter[] calldata reporters, IAdapter[] calldata adapters ) external payable returns (uint256[] memory, bytes32[] memory) { if (thresholds.length != receivers.length) revert UnequalArrayLengths(thresholds.length, receivers.length); if (thresholds.length != data.length) revert UnequalArrayLengths(thresholds.length, data.length); uint256[] memory messageIds = new uint256[](receivers.length); bytes32[] memory messageHashes = new bytes32[](receivers.length); for (uint256 i = 0; i < receivers.length; ) { _checkReportersAndAdapters(thresholds[i], reporters, adapters); (messageIds[i], messageHashes[i]) = _dispatchMessage( targetChainId, thresholds[i], receivers[i], data[i], reporters, adapters ); unchecked { ++i; } } bytes32[] memory reportersReceipts = new bytes32[](reporters.length); reportersReceipts = _dispatchMessagesToAdapters(targetChainId, messageIds, messageHashes, reporters, adapters); return (messageIds, reportersReceipts); } /// @inheritdoc IYaho function getPendingMessageHash(uint256 messageId) external view returns (bytes32) { return _pendingMessageHashes[messageId]; } /// @inheritdoc IYaho function relayMessagesToAdapters(Message[] calldata messages) external payable returns (bytes32[] memory) { if (messages.length == 0) revert NoMessagesGiven(); bytes32 expectedParams = keccak256( abi.encode(messages[0].targetChainId, messages[0].reporters, messages[0].adapters) ); bytes32[] memory messageHashes = new bytes32[](messages.length); uint256[] memory messageIds = new uint256[](messages.length); for (uint256 i = 0; i < messages.length; i++) { Message memory message = messages[i]; if ( i > 0 && expectedParams != keccak256(abi.encode(message.targetChainId, message.reporters, message.adapters)) ) revert InvalidMessage(message); uint256 messageId = calculateMessageId(block.chainid, address(this), calculateMessageHash(message)); bytes32 messageHash = _pendingMessageHashes[messageId]; if (messageHash == bytes32(0)) revert MessageHashNotFound(messageId); messageHashes[i] = messageHash; messageIds[i] = messageId; delete _pendingMessageHashes[messageId]; } return _dispatchMessagesToAdapters( messages[0].targetChainId, messageIds, messageHashes, messages[0].reporters, messages[0].adapters ); } function _checkReportersAndAdapters( uint256 threshold, IReporter[] calldata reporters, IAdapter[] calldata adapters ) internal pure { if (reporters.length == 0) revert NoReportersGiven(); if (adapters.length == 0) revert NoAdaptersGiven(); if (reporters.length != adapters.length) revert UnequalArrayLengths(reporters.length, adapters.length); if (threshold > reporters.length || threshold == 0) revert InvalidThreshold(threshold, reporters.length); } function _dispatchMessage( uint256 targetChainId, uint256 threshold, address receiver, bytes calldata data, IReporter[] calldata reporters, IAdapter[] calldata adapters ) internal returns (uint256, bytes32) { address sender = msg.sender; Message memory message = Message( currentNonce, targetChainId, threshold, sender, receiver, data, reporters, adapters ); bytes32 messageHash = calculateMessageHash(message); uint256 messageId = calculateMessageId(block.chainid, address(this), messageHash); unchecked { ++currentNonce; } emit MessageDispatched(messageId, message); return (messageId, messageHash); } function _dispatchMessageToAdapters( uint256 targetChainId, uint256 messageId, bytes32 messageHash, IReporter[] memory reporters, IAdapter[] memory adapters ) internal returns (bytes32[] memory) { uint256[] memory messageIds = new uint256[](1); bytes32[] memory messageHashes = new bytes32[](1); messageIds[0] = messageId; messageHashes[0] = messageHash; return _dispatchMessagesToAdapters(targetChainId, messageIds, messageHashes, reporters, adapters); } function _dispatchMessagesToAdapters( uint256 targetChainId, uint256[] memory messageIds, bytes32[] memory messageHashes, IReporter[] memory reporters, IAdapter[] memory adapters ) internal returns (bytes32[] memory) { bytes32[] memory reportersReceipts = new bytes32[](reporters.length); for (uint256 i = 0; i < reporters.length; ) { IReporter reporter = reporters[i]; if (address(reporter) != address(0)) { reportersReceipts[i] = reporter.dispatchMessages(targetChainId, adapters[i], messageIds, messageHashes); } unchecked { ++i; } } return reportersReceipts; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IUpgradable } from '../interfaces/IUpgradable.sol'; /** * @title IAxelarGasService Interface * @notice This is an interface for the AxelarGasService contract which manages gas payments * and refunds for cross-chain communication on the Axelar network. * @dev This interface inherits IUpgradable */ interface IAxelarGasService is IUpgradable { error NothingReceived(); error InvalidAddress(); error NotCollector(); error InvalidAmounts(); event GasPaidForContractCall( address indexed sourceAddress, string destinationChain, string destinationAddress, bytes32 indexed payloadHash, address gasToken, uint256 gasFeeAmount, address refundAddress ); event GasPaidForContractCallWithToken( address indexed sourceAddress, string destinationChain, string destinationAddress, bytes32 indexed payloadHash, string symbol, uint256 amount, address gasToken, uint256 gasFeeAmount, address refundAddress ); event NativeGasPaidForContractCall( address indexed sourceAddress, string destinationChain, string destinationAddress, bytes32 indexed payloadHash, uint256 gasFeeAmount, address refundAddress ); event NativeGasPaidForContractCallWithToken( address indexed sourceAddress, string destinationChain, string destinationAddress, bytes32 indexed payloadHash, string symbol, uint256 amount, uint256 gasFeeAmount, address refundAddress ); event GasPaidForExpressCall( address indexed sourceAddress, string destinationChain, string destinationAddress, bytes32 indexed payloadHash, address gasToken, uint256 gasFeeAmount, address refundAddress ); event GasPaidForExpressCallWithToken( address indexed sourceAddress, string destinationChain, string destinationAddress, bytes32 indexed payloadHash, string symbol, uint256 amount, address gasToken, uint256 gasFeeAmount, address refundAddress ); event NativeGasPaidForExpressCall( address indexed sourceAddress, string destinationChain, string destinationAddress, bytes32 indexed payloadHash, uint256 gasFeeAmount, address refundAddress ); event NativeGasPaidForExpressCallWithToken( address indexed sourceAddress, string destinationChain, string destinationAddress, bytes32 indexed payloadHash, string symbol, uint256 amount, uint256 gasFeeAmount, address refundAddress ); event GasAdded( bytes32 indexed txHash, uint256 indexed logIndex, address gasToken, uint256 gasFeeAmount, address refundAddress ); event NativeGasAdded(bytes32 indexed txHash, uint256 indexed logIndex, uint256 gasFeeAmount, address refundAddress); event ExpressGasAdded( bytes32 indexed txHash, uint256 indexed logIndex, address gasToken, uint256 gasFeeAmount, address refundAddress ); event NativeExpressGasAdded( bytes32 indexed txHash, uint256 indexed logIndex, uint256 gasFeeAmount, address refundAddress ); event Refunded( bytes32 indexed txHash, uint256 indexed logIndex, address payable receiver, address token, uint256 amount ); /** * @notice Pay for gas using ERC20 tokens for a contract call on a destination chain. * @dev This function is called on the source chain before calling the gateway to execute a remote contract. * @param sender The address making the payment * @param destinationChain The target chain where the contract call will be made * @param destinationAddress The target address on the destination chain * @param payload Data payload for the contract call * @param gasToken The address of the ERC20 token used to pay for gas * @param gasFeeAmount The amount of tokens to pay for gas * @param refundAddress The address where refunds, if any, should be sent */ function payGasForContractCall( address sender, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, address gasToken, uint256 gasFeeAmount, address refundAddress ) external; /** * @notice Pay for gas using ERC20 tokens for a contract call with tokens on a destination chain. * @dev This function is called on the source chain before calling the gateway to execute a remote contract. * @param sender The address making the payment * @param destinationChain The target chain where the contract call with tokens will be made * @param destinationAddress The target address on the destination chain * @param payload Data payload for the contract call with tokens * @param symbol The symbol of the token to be sent with the call * @param amount The amount of tokens to be sent with the call * @param gasToken The address of the ERC20 token used to pay for gas * @param gasFeeAmount The amount of tokens to pay for gas * @param refundAddress The address where refunds, if any, should be sent */ function payGasForContractCallWithToken( address sender, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, string calldata symbol, uint256 amount, address gasToken, uint256 gasFeeAmount, address refundAddress ) external; /** * @notice Pay for gas using native currency for a contract call on a destination chain. * @dev This function is called on the source chain before calling the gateway to execute a remote contract. * @param sender The address making the payment * @param destinationChain The target chain where the contract call will be made * @param destinationAddress The target address on the destination chain * @param payload Data payload for the contract call * @param refundAddress The address where refunds, if any, should be sent */ function payNativeGasForContractCall( address sender, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, address refundAddress ) external payable; /** * @notice Pay for gas using native currency for a contract call with tokens on a destination chain. * @dev This function is called on the source chain before calling the gateway to execute a remote contract. * @param sender The address making the payment * @param destinationChain The target chain where the contract call with tokens will be made * @param destinationAddress The target address on the destination chain * @param payload Data payload for the contract call with tokens * @param symbol The symbol of the token to be sent with the call * @param amount The amount of tokens to be sent with the call * @param refundAddress The address where refunds, if any, should be sent */ function payNativeGasForContractCallWithToken( address sender, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, string calldata symbol, uint256 amount, address refundAddress ) external payable; /** * @notice Pay for gas using ERC20 tokens for an express contract call on a destination chain. * @dev This function is called on the source chain before calling the gateway to express execute a remote contract. * @param sender The address making the payment * @param destinationChain The target chain where the contract call will be made * @param destinationAddress The target address on the destination chain * @param payload Data payload for the contract call * @param gasToken The address of the ERC20 token used to pay for gas * @param gasFeeAmount The amount of tokens to pay for gas * @param refundAddress The address where refunds, if any, should be sent */ function payGasForExpressCall( address sender, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, address gasToken, uint256 gasFeeAmount, address refundAddress ) external; /** * @notice Pay for gas using ERC20 tokens for an express contract call with tokens on a destination chain. * @dev This function is called on the source chain before calling the gateway to express execute a remote contract. * @param sender The address making the payment * @param destinationChain The target chain where the contract call with tokens will be made * @param destinationAddress The target address on the destination chain * @param payload Data payload for the contract call with tokens * @param symbol The symbol of the token to be sent with the call * @param amount The amount of tokens to be sent with the call * @param gasToken The address of the ERC20 token used to pay for gas * @param gasFeeAmount The amount of tokens to pay for gas * @param refundAddress The address where refunds, if any, should be sent */ function payGasForExpressCallWithToken( address sender, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, string calldata symbol, uint256 amount, address gasToken, uint256 gasFeeAmount, address refundAddress ) external; /** * @notice Pay for gas using native currency for an express contract call on a destination chain. * @dev This function is called on the source chain before calling the gateway to express execute a remote contract. * @param sender The address making the payment * @param destinationChain The target chain where the contract call will be made * @param destinationAddress The target address on the destination chain * @param payload Data payload for the contract call * @param refundAddress The address where refunds, if any, should be sent */ function payNativeGasForExpressCall( address sender, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, address refundAddress ) external payable; /** * @notice Pay for gas using native currency for an express contract call with tokens on a destination chain. * @dev This function is called on the source chain before calling the gateway to express execute a remote contract. * @param sender The address making the payment * @param destinationChain The target chain where the contract call with tokens will be made * @param destinationAddress The target address on the destination chain * @param payload Data payload for the contract call with tokens * @param symbol The symbol of the token to be sent with the call * @param amount The amount of tokens to be sent with the call * @param refundAddress The address where refunds, if any, should be sent */ function payNativeGasForExpressCallWithToken( address sender, string calldata destinationChain, string calldata destinationAddress, bytes calldata payload, string calldata symbol, uint256 amount, address refundAddress ) external payable; /** * @notice Add additional gas payment using ERC20 tokens after initiating a cross-chain call. * @dev This function can be called on the source chain after calling the gateway to execute a remote contract. * @param txHash The transaction hash of the cross-chain call * @param logIndex The log index for the cross-chain call * @param gasToken The ERC20 token address used to add gas * @param gasFeeAmount The amount of tokens to add as gas * @param refundAddress The address where refunds, if any, should be sent */ function addGas( bytes32 txHash, uint256 logIndex, address gasToken, uint256 gasFeeAmount, address refundAddress ) external; /** * @notice Add additional gas payment using native currency after initiating a cross-chain call. * @dev This function can be called on the source chain after calling the gateway to execute a remote contract. * @param txHash The transaction hash of the cross-chain call * @param logIndex The log index for the cross-chain call * @param refundAddress The address where refunds, if any, should be sent */ function addNativeGas( bytes32 txHash, uint256 logIndex, address refundAddress ) external payable; /** * @notice Add additional gas payment using ERC20 tokens after initiating an express cross-chain call. * @dev This function can be called on the source chain after calling the gateway to express execute a remote contract. * @param txHash The transaction hash of the cross-chain call * @param logIndex The log index for the cross-chain call * @param gasToken The ERC20 token address used to add gas * @param gasFeeAmount The amount of tokens to add as gas * @param refundAddress The address where refunds, if any, should be sent */ function addExpressGas( bytes32 txHash, uint256 logIndex, address gasToken, uint256 gasFeeAmount, address refundAddress ) external; /** * @notice Add additional gas payment using native currency after initiating an express cross-chain call. * @dev This function can be called on the source chain after calling the gateway to express execute a remote contract. * @param txHash The transaction hash of the cross-chain call * @param logIndex The log index for the cross-chain call * @param refundAddress The address where refunds, if any, should be sent */ function addNativeExpressGas( bytes32 txHash, uint256 logIndex, address refundAddress ) external payable; /** * @notice Allows the gasCollector to collect accumulated fees from the contract. * @dev Use address(0) as the token address for native currency. * @param receiver The address to receive the collected fees * @param tokens Array of token addresses to be collected * @param amounts Array of amounts to be collected for each respective token address */ function collectFees( address payable receiver, address[] calldata tokens, uint256[] calldata amounts ) external; /** * @notice Refunds gas payment to the receiver in relation to a specific cross-chain transaction. * @dev Only callable by the gasCollector. * @dev Use address(0) as the token address to refund native currency. * @param txHash The transaction hash of the cross-chain call * @param logIndex The log index for the cross-chain call * @param receiver The address to receive the refund * @param token The token address to be refunded * @param amount The amount to refund */ function refund( bytes32 txHash, uint256 logIndex, address payable receiver, address token, uint256 amount ) external; /** * @notice Returns the address of the designated gas collector. * @return address of the gas collector */ function gasCollector() external returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IGovernable } from './IGovernable.sol'; import { IImplementation } from './IImplementation.sol'; interface IAxelarGateway is IImplementation, IGovernable { /**********\ |* Errors *| \**********/ error NotSelf(); error InvalidCodeHash(); error SetupFailed(); error InvalidAuthModule(); error InvalidTokenDeployer(); error InvalidAmount(); error InvalidChainId(); error InvalidCommands(); error TokenDoesNotExist(string symbol); error TokenAlreadyExists(string symbol); error TokenDeployFailed(string symbol); error TokenContractDoesNotExist(address token); error BurnFailed(string symbol); error MintFailed(string symbol); error InvalidSetMintLimitsParams(); error ExceedMintLimit(string symbol); /**********\ |* Events *| \**********/ event TokenSent( address indexed sender, string destinationChain, string destinationAddress, string symbol, uint256 amount ); event ContractCall( address indexed sender, string destinationChain, string destinationContractAddress, bytes32 indexed payloadHash, bytes payload ); event ContractCallWithToken( address indexed sender, string destinationChain, string destinationContractAddress, bytes32 indexed payloadHash, bytes payload, string symbol, uint256 amount ); event Executed(bytes32 indexed commandId); event TokenDeployed(string symbol, address tokenAddresses); event ContractCallApproved( bytes32 indexed commandId, string sourceChain, string sourceAddress, address indexed contractAddress, bytes32 indexed payloadHash, bytes32 sourceTxHash, uint256 sourceEventIndex ); event ContractCallApprovedWithMint( bytes32 indexed commandId, string sourceChain, string sourceAddress, address indexed contractAddress, bytes32 indexed payloadHash, string symbol, uint256 amount, bytes32 sourceTxHash, uint256 sourceEventIndex ); event ContractCallExecuted(bytes32 indexed commandId); event TokenMintLimitUpdated(string symbol, uint256 limit); event OperatorshipTransferred(bytes newOperatorsData); event Upgraded(address indexed implementation); /********************\ |* Public Functions *| \********************/ function sendToken( string calldata destinationChain, string calldata destinationAddress, string calldata symbol, uint256 amount ) external; function callContract( string calldata destinationChain, string calldata contractAddress, bytes calldata payload ) external; function callContractWithToken( string calldata destinationChain, string calldata contractAddress, bytes calldata payload, string calldata symbol, uint256 amount ) external; function isContractCallApproved( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, address contractAddress, bytes32 payloadHash ) external view returns (bool); function isContractCallAndMintApproved( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, address contractAddress, bytes32 payloadHash, string calldata symbol, uint256 amount ) external view returns (bool); function validateContractCall( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes32 payloadHash ) external returns (bool); function validateContractCallAndMint( bytes32 commandId, string calldata sourceChain, string calldata sourceAddress, bytes32 payloadHash, string calldata symbol, uint256 amount ) external returns (bool); /***********\ |* Getters *| \***********/ function authModule() external view returns (address); function tokenDeployer() external view returns (address); function tokenMintLimit(string memory symbol) external view returns (uint256); function tokenMintAmount(string memory symbol) external view returns (uint256); function allTokensFrozen() external view returns (bool); function implementation() external view returns (address); function tokenAddresses(string memory symbol) external view returns (address); function tokenFrozen(string memory symbol) external view returns (bool); function isCommandExecuted(bytes32 commandId) external view returns (bool); /************************\ |* Governance Functions *| \************************/ function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external; function upgrade( address newImplementation, bytes32 newImplementationCodeHash, bytes calldata setupParams ) external; /**********************\ |* External Functions *| \**********************/ function execute(bytes calldata input) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // General interface for upgradable contracts interface IContractIdentifier { /** * @notice Returns the contract ID. It can be used as a check during upgrades. * @dev Meant to be overridden in derived contracts. * @return bytes32 The contract ID */ function contractId() external pure returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IGovernable Interface * @notice This is an interface used by the AxelarGateway contract to manage governance and mint limiter roles. */ interface IGovernable { error NotGovernance(); error NotMintLimiter(); error InvalidGovernance(); error InvalidMintLimiter(); event GovernanceTransferred(address indexed previousGovernance, address indexed newGovernance); event MintLimiterTransferred(address indexed previousGovernance, address indexed newGovernance); /** * @notice Returns the governance address. * @return address of the governance */ function governance() external view returns (address); /** * @notice Returns the mint limiter address. * @return address of the mint limiter */ function mintLimiter() external view returns (address); /** * @notice Transfer the governance role to another address. * @param newGovernance The new governance address */ function transferGovernance(address newGovernance) external; /** * @notice Transfer the mint limiter role to another address. * @param newGovernance The new mint limiter address */ function transferMintLimiter(address newGovernance) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IContractIdentifier } from './IContractIdentifier.sol'; interface IImplementation is IContractIdentifier { error NotProxy(); function setup(bytes calldata data) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title IOwnable Interface * @notice IOwnable is an interface that abstracts the implementation of a * contract with ownership control features. It's commonly used in upgradable * contracts and includes the functionality to get current owner, transfer * ownership, and propose and accept ownership. */ interface IOwnable { error NotOwner(); error InvalidOwner(); error InvalidOwnerAddress(); event OwnershipTransferStarted(address indexed newOwner); event OwnershipTransferred(address indexed newOwner); /** * @notice Returns the current owner of the contract. * @return address The address of the current owner */ function owner() external view returns (address); /** * @notice Returns the address of the pending owner of the contract. * @return address The address of the pending owner */ function pendingOwner() external view returns (address); /** * @notice Transfers ownership of the contract to a new address * @param newOwner The address to transfer ownership to */ function transferOwnership(address newOwner) external; /** * @notice Proposes to transfer the contract's ownership to a new address. * The new owner needs to accept the ownership explicitly. * @param newOwner The address to transfer ownership to */ function proposeOwnership(address newOwner) external; /** * @notice Transfers ownership to the pending owner. * @dev Can only be called by the pending owner */ function acceptOwnership() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IOwnable } from './IOwnable.sol'; import { IImplementation } from './IImplementation.sol'; // General interface for upgradable contracts interface IUpgradable is IOwnable, IImplementation { error InvalidCodeHash(); error InvalidImplementation(); error SetupFailed(); event Upgraded(address indexed newImplementation); function implementation() external view returns (address); function upgrade( address newImplementation, bytes32 newImplementationCodeHash, bytes calldata params ) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.17; import {ExecuteArgs, TransferInfo, DestinationTransferStatus} from "../libraries/LibConnextStorage.sol"; import {TokenId} from "../libraries/TokenId.sol"; interface IConnext { // ============ BRIDGE ============== function xcall( uint32 _destination, address _to, address _asset, address _delegate, uint256 _amount, uint256 _slippage, bytes calldata _callData ) external payable returns (bytes32); function xcallIntoLocal( uint32 _destination, address _to, address _asset, address _delegate, uint256 _amount, uint256 _slippage, bytes calldata _callData ) external payable returns (bytes32); function execute(ExecuteArgs calldata _args) external returns (bytes32 transferId); function forceUpdateSlippage(TransferInfo calldata _params, uint256 _slippage) external; function forceReceiveLocal(TransferInfo calldata _params) external; function bumpTransfer(bytes32 _transferId) external payable; function routedTransfers(bytes32 _transferId) external view returns (address[] memory); function transferStatus(bytes32 _transferId) external view returns (DestinationTransferStatus); function remote(uint32 _domain) external view returns (address); function domain() external view returns (uint256); function nonce() external view returns (uint256); function approvedSequencers(address _sequencer) external view returns (bool); function xAppConnectionManager() external view returns (address); // ============ ROUTERS ============== function LIQUIDITY_FEE_NUMERATOR() external view returns (uint256); function LIQUIDITY_FEE_DENOMINATOR() external view returns (uint256); function getRouterApproval(address _router) external view returns (bool); function getRouterRecipient(address _router) external view returns (address); function getRouterOwner(address _router) external view returns (address); function getProposedRouterOwner(address _router) external view returns (address); function getProposedRouterOwnerTimestamp(address _router) external view returns (uint256); function maxRoutersPerTransfer() external view returns (uint256); function routerBalances(address _router, address _asset) external view returns (uint256); function getRouterApprovalForPortal(address _router) external view returns (bool); function initializeRouter(address _owner, address _recipient) external; function setRouterRecipient(address _router, address _recipient) external; function proposeRouterOwner(address _router, address _proposed) external; function acceptProposedRouterOwner(address _router) external; function addRouterLiquidityFor( uint256 _amount, address _local, address _router ) external payable; function addRouterLiquidity(uint256 _amount, address _local) external payable; function removeRouterLiquidityFor( TokenId memory _canonical, uint256 _amount, address payable _to, address _router ) external; function removeRouterLiquidity(TokenId memory _canonical, uint256 _amount, address payable _to) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.17; interface IXReceiver { function xReceive( bytes32 _transferId, uint256 _amount, address _asset, address _originSender, uint32 _origin, bytes memory _callData ) external returns (bytes memory); }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.17; /** * @notice Enum representing status of destination transfer * @dev Status is only assigned on the destination domain, will always be "none" for the * origin domains * @return uint - Index of value in enum */ enum DestinationTransferStatus { None, // 0 Reconciled, // 1 Executed, // 2 Completed // 3 - executed + reconciled } /** * @notice These are the parameters that will remain constant between the * two chains. They are supplied on `xcall` and should be asserted on `execute` * @property to - The account that receives funds, in the event of a crosschain call, * will receive funds if the call fails. * * @param originDomain - The originating domain (i.e. where `xcall` is called) * @param destinationDomain - The final domain (i.e. where `execute` / `reconcile` are called)\ * @param canonicalDomain - The canonical domain of the asset you are bridging * @param to - The address you are sending funds (and potentially data) to * @param delegate - An address who can execute txs on behalf of `to`, in addition to allowing relayers * @param receiveLocal - If true, will use the local asset on the destination instead of adopted. * @param callData - The data to execute on the receiving chain. If no crosschain call is needed, then leave empty. * @param slippage - Slippage user is willing to accept from original amount in expressed in BPS (i.e. if * a user takes 1% slippage, this is expressed as 1_000) * @param originSender - The msg.sender of the xcall * @param bridgedAmt - The amount sent over the bridge (after potential AMM on xcall) * @param normalizedIn - The amount sent to `xcall`, normalized to 18 decimals * @param nonce - The nonce on the origin domain used to ensure the transferIds are unique * @param canonicalId - The unique identifier of the canonical token corresponding to bridge assets */ struct TransferInfo { uint32 originDomain; uint32 destinationDomain; uint32 canonicalDomain; address to; address delegate; bool receiveLocal; bytes callData; uint256 slippage; address originSender; uint256 bridgedAmt; uint256 normalizedIn; uint256 nonce; bytes32 canonicalId; } /** * @notice * @param params - The TransferInfo. These are consistent across sending and receiving chains. * @param routers - The routers who you are sending the funds on behalf of. * @param routerSignatures - Signatures belonging to the routers indicating permission to use funds * for the signed transfer ID. * @param sequencer - The sequencer who assigned the router path to this transfer. * @param sequencerSignature - Signature produced by the sequencer for path assignment accountability * for the path that was signed. */ struct ExecuteArgs { TransferInfo params; address[] routers; bytes[] routerSignatures; address sequencer; bytes sequencerSignature; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity ^0.8.17; // ============= Structs ============= // Tokens are identified by a TokenId: // domain - 4 byte chain ID of the chain from which the token originates // id - 32 byte identifier of the token address on the origin chain, in that chain's address format struct TokenId { uint32 domain; bytes32 id; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.8.0; /*@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@ HYPERLANE @@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@*/ interface IPostDispatchHook { enum Types { UNUSED, ROUTING, AGGREGATION, MERKLE_TREE, INTERCHAIN_GAS_PAYMASTER, FALLBACK_ROUTING, ID_AUTH_ISM, PAUSABLE, PROTOCOL_FEE } /** * @notice Returns an enum that represents the type of hook */ function hookType() external view returns (uint8); /** * @notice Returns whether the hook supports metadata * @param metadata metadata * @return Whether the hook supports metadata */ function supportsMetadata( bytes calldata metadata ) external view returns (bool); /** * @notice Post action after a message is dispatched via the Mailbox * @param metadata The metadata required for the hook * @param message The message passed from the Mailbox.dispatch() call */ function postDispatch( bytes calldata metadata, bytes calldata message ) external payable; /** * @notice Compute the payment required by the postDispatch call * @param metadata The metadata required for the hook * @param message The message passed from the Mailbox.dispatch() call * @return Quoted payment for the postDispatch call */ function quoteDispatch( bytes calldata metadata, bytes calldata message ) external view returns (uint256); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.6.11; interface IInterchainSecurityModule { enum Types { UNUSED, ROUTING, AGGREGATION, LEGACY_MULTISIG, MERKLE_ROOT_MULTISIG, MESSAGE_ID_MULTISIG, NULL, // used with relayer carrying no metadata CCIP_READ } /** * @notice Returns an enum that represents the type of security model * encoded by this ISM. * @dev Relayers infer how to fetch and format metadata. */ function moduleType() external view returns (uint8); /** * @notice Defines a security model responsible for verifying interchain * messages based on the provided metadata. * @param _metadata Off-chain metadata provided by a relayer, specific to * the security model encoded by the module (e.g. validator signatures) * @param _message Hyperlane encoded interchain message * @return True if the message was verified */ function verify( bytes calldata _metadata, bytes calldata _message ) external returns (bool); } interface ISpecifiesInterchainSecurityModule { function interchainSecurityModule() external view returns (IInterchainSecurityModule); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.8.0; import {IInterchainSecurityModule} from "./IInterchainSecurityModule.sol"; import {IPostDispatchHook} from "./hooks/IPostDispatchHook.sol"; interface IMailbox { // ============ Events ============ /** * @notice Emitted when a new message is dispatched via Hyperlane * @param sender The address that dispatched the message * @param destination The destination domain of the message * @param recipient The message recipient address on `destination` * @param message Raw bytes of message */ event Dispatch( address indexed sender, uint32 indexed destination, bytes32 indexed recipient, bytes message ); /** * @notice Emitted when a new message is dispatched via Hyperlane * @param messageId The unique message identifier */ event DispatchId(bytes32 indexed messageId); /** * @notice Emitted when a Hyperlane message is processed * @param messageId The unique message identifier */ event ProcessId(bytes32 indexed messageId); /** * @notice Emitted when a Hyperlane message is delivered * @param origin The origin domain of the message * @param sender The message sender address on `origin` * @param recipient The address that handled the message */ event Process( uint32 indexed origin, bytes32 indexed sender, address indexed recipient ); function localDomain() external view returns (uint32); function delivered(bytes32 messageId) external view returns (bool); function defaultIsm() external view returns (IInterchainSecurityModule); function defaultHook() external view returns (IPostDispatchHook); function requiredHook() external view returns (IPostDispatchHook); function latestDispatchedId() external view returns (bytes32); function dispatch( uint32 destinationDomain, bytes32 recipientAddress, bytes calldata messageBody ) external payable returns (bytes32 messageId); function quoteDispatch( uint32 destinationDomain, bytes32 recipientAddress, bytes calldata messageBody ) external view returns (uint256 fee); function dispatch( uint32 destinationDomain, bytes32 recipientAddress, bytes calldata body, bytes calldata defaultHookMetadata ) external payable returns (bytes32 messageId); function quoteDispatch( uint32 destinationDomain, bytes32 recipientAddress, bytes calldata messageBody, bytes calldata defaultHookMetadata ) external view returns (uint256 fee); function dispatch( uint32 destinationDomain, bytes32 recipientAddress, bytes calldata body, bytes calldata customHookMetadata, IPostDispatchHook customHook ) external payable returns (bytes32 messageId); function quoteDispatch( uint32 destinationDomain, bytes32 recipientAddress, bytes calldata messageBody, bytes calldata customHookMetadata, IPostDispatchHook customHook ) external view returns (uint256 fee); function process( bytes calldata metadata, bytes calldata message ) external payable; function recipientIsm( address recipient ) external view returns (IInterchainSecurityModule module); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.6.11; library TypeCasts { // alignment preserving cast function addressToBytes32(address _addr) internal pure returns (bytes32) { return bytes32(uint256(uint160(_addr))); } // alignment preserving cast function bytes32ToAddress(bytes32 _buf) internal pure returns (address) { return address(uint160(uint256(_buf))); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1820Registry.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC1820RegistryUpgradeable.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/draft-IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20Upgradeable { using AddressUpgradeable for address; function safeTransfer( IERC20Upgradeable token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20Upgradeable token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20Upgradeable token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC777/IERC777Recipient.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP. * * Accounts can be notified of {IERC777} tokens being sent to them by having a * contract implement this interface (contract holders can be their own * implementer) and registering it on the * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. * * See {IERC1820Registry} and {ERC1820Implementer}. */ interface IERC777RecipientUpgradeable { /** * @dev Called by an {IERC777} token contract whenever tokens are being * moved or created into a registered account (`to`). The type of operation * is conveyed by `from` being the zero address or not. * * This call occurs _after_ the token contract's state is updated, so * {IERC777-balanceOf}, etc., can be used to query the post-operation state. * * This function may revert to prevent the operation from being executed. */ function tokensReceived( address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC777/IERC777.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC777Token standard as defined in the EIP. * * This contract uses the * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let * token holders and recipients react to token movements by using setting implementers * for the associated interfaces in said registry. See {IERC1820Registry} and * {ERC1820Implementer}. */ interface IERC777Upgradeable { /** * @dev Emitted when `amount` tokens are created by `operator` and assigned to `to`. * * Note that some additional user `data` and `operatorData` can be logged in the event. */ event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); /** * @dev Emitted when `operator` destroys `amount` tokens from `account`. * * Note that some additional user `data` and `operatorData` can be logged in the event. */ event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); /** * @dev Emitted when `operator` is made operator for `tokenHolder`. */ event AuthorizedOperator(address indexed operator, address indexed tokenHolder); /** * @dev Emitted when `operator` is revoked its operator status for `tokenHolder`. */ event RevokedOperator(address indexed operator, address indexed tokenHolder); /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() external view returns (string memory); /** * @dev Returns the smallest part of the token that is not divisible. This * means all token operations (creation, movement and destruction) must have * amounts that are a multiple of this number. * * For most token contracts, this value will equal 1. */ function granularity() external view returns (uint256); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by an account (`owner`). */ function balanceOf(address owner) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * If send or receive hooks are registered for the caller and `recipient`, * the corresponding functions will be called with `data` and empty * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. * * Emits a {Sent} event. * * Requirements * * - the caller must have at least `amount` tokens. * - `recipient` cannot be the zero address. * - if `recipient` is a contract, it must implement the {IERC777Recipient} * interface. */ function send( address recipient, uint256 amount, bytes calldata data ) external; /** * @dev Destroys `amount` tokens from the caller's account, reducing the * total supply. * * If a send hook is registered for the caller, the corresponding function * will be called with `data` and empty `operatorData`. See {IERC777Sender}. * * Emits a {Burned} event. * * Requirements * * - the caller must have at least `amount` tokens. */ function burn(uint256 amount, bytes calldata data) external; /** * @dev Returns true if an account is an operator of `tokenHolder`. * Operators can send and burn tokens on behalf of their owners. All * accounts are their own operator. * * See {operatorSend} and {operatorBurn}. */ function isOperatorFor(address operator, address tokenHolder) external view returns (bool); /** * @dev Make an account an operator of the caller. * * See {isOperatorFor}. * * Emits an {AuthorizedOperator} event. * * Requirements * * - `operator` cannot be calling address. */ function authorizeOperator(address operator) external; /** * @dev Revoke an account's operator status for the caller. * * See {isOperatorFor} and {defaultOperators}. * * Emits a {RevokedOperator} event. * * Requirements * * - `operator` cannot be calling address. */ function revokeOperator(address operator) external; /** * @dev Returns the list of default operators. These accounts are operators * for all token holders, even if {authorizeOperator} was never called on * them. * * This list is immutable, but individual holders may revoke these via * {revokeOperator}, in which case {isOperatorFor} will return false. */ function defaultOperators() external view returns (address[] memory); /** * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must * be an operator of `sender`. * * If send or receive hooks are registered for `sender` and `recipient`, * the corresponding functions will be called with `data` and * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. * * Emits a {Sent} event. * * Requirements * * - `sender` cannot be the zero address. * - `sender` must have at least `amount` tokens. * - the caller must be an operator for `sender`. * - `recipient` cannot be the zero address. * - if `recipient` is a contract, it must implement the {IERC777Recipient} * interface. */ function operatorSend( address sender, address recipient, uint256 amount, bytes calldata data, bytes calldata operatorData ) external; /** * @dev Destroys `amount` tokens from `account`, reducing the total supply. * The caller must be an operator of `account`. * * If a send hook is registered for `account`, the corresponding function * will be called with `data` and `operatorData`. See {IERC777Sender}. * * Emits a {Burned} event. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. * - the caller must be an operator for `account`. */ function operatorBurn( address account, uint256 amount, bytes calldata data, bytes calldata operatorData ) external; event Sent( address indexed operator, address indexed from, address indexed to, uint256 amount, bytes data, bytes operatorData ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/introspection/IERC1820Registry.sol) pragma solidity ^0.8.0; /** * @dev Interface of the global ERC1820 Registry, as defined in the * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register * implementers for interfaces in this registry, as well as query support. * * Implementers may be shared by multiple accounts, and can also implement more * than a single interface for each account. Contracts can implement interfaces * for themselves, but externally-owned accounts (EOA) must delegate this to a * contract. * * {IERC165} interfaces can also be queried via the registry. * * For an in-depth explanation and source code analysis, see the EIP text. */ interface IERC1820RegistryUpgradeable { event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer); event ManagerChanged(address indexed account, address indexed newManager); /** * @dev Sets `newManager` as the manager for `account`. A manager of an * account is able to set interface implementers for it. * * By default, each account is its own manager. Passing a value of `0x0` in * `newManager` will reset the manager to this initial state. * * Emits a {ManagerChanged} event. * * Requirements: * * - the caller must be the current manager for `account`. */ function setManager(address account, address newManager) external; /** * @dev Returns the manager for `account`. * * See {setManager}. */ function getManager(address account) external view returns (address); /** * @dev Sets the `implementer` contract as ``account``'s implementer for * `interfaceHash`. * * `account` being the zero address is an alias for the caller's address. * The zero address can also be used in `implementer` to remove an old one. * * See {interfaceHash} to learn how these are created. * * Emits an {InterfaceImplementerSet} event. * * Requirements: * * - the caller must be the current manager for `account`. * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not * end in 28 zeroes). * - `implementer` must implement {IERC1820Implementer} and return true when * queried for support, unless `implementer` is the caller. See * {IERC1820Implementer-canImplementInterfaceForAddress}. */ function setInterfaceImplementer( address account, bytes32 _interfaceHash, address implementer ) external; /** * @dev Returns the implementer of `interfaceHash` for `account`. If no such * implementer is registered, returns the zero address. * * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28 * zeroes), `account` will be queried for support of it. * * `account` being the zero address is an alias for the caller's address. */ function getInterfaceImplementer(address account, bytes32 _interfaceHash) external view returns (address); /** * @dev Returns the interface hash for an `interfaceName`, as defined in the * corresponding * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP]. */ function interfaceHash(string calldata interfaceName) external pure returns (bytes32); /** * @notice Updates the cache with whether the contract implements an ERC165 interface or not. * @param account Address of the contract for which to update the cache. * @param interfaceId ERC165 interface for which to update the cache. */ function updateERC165Cache(address account, bytes4 interfaceId) external; /** * @notice Checks whether a contract implements an ERC165 interface or not. * If the result is not cached a direct lookup on the contract address is performed. * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling * {updateERC165Cache} with the contract address. * @param account Address of the contract to check. * @param interfaceId ERC165 interface to check. * @return True if `account` implements `interfaceId`, false otherwise. */ function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool); /** * @notice Checks whether a contract implements an ERC165 interface or not without using or updating the cache. * @param account Address of the contract to check. * @param interfaceId ERC165 interface to check. * @return True if `account` implements `interfaceId`, false otherwise. */ function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSetUpgradeable { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC777Recipient.sol) pragma solidity ^0.8.0; import "../token/ERC777/IERC777Recipient.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC777/IERC777Recipient.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP. * * Accounts can be notified of {IERC777} tokens being sent to them by having a * contract implement this interface (contract holders can be their own * implementer) and registering it on the * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. * * See {IERC1820Registry} and {ERC1820Implementer}. */ interface IERC777Recipient { /** * @dev Called by an {IERC777} token contract whenever tokens are being * moved or created into a registered account (`to`). The type of operation * is conveyed by `from` being the zero address or not. * * This call occurs _after_ the token contract's state is updated, so * {IERC777-balanceOf}, etc., can be used to query the post-operation state. * * This function may revert to prevent the operation from being executed. */ function tokensReceived( address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { IAdapter } from "../interfaces/IAdapter.sol"; abstract contract Adapter is IAdapter { mapping(uint256 => mapping(uint256 => bytes32)) private _hashes; /// @inheritdoc IAdapter function getHash(uint256 domain, uint256 id) public view returns (bytes32) { return _hashes[domain][id]; } function _storeHashes(uint256 domain, uint256[] memory ids, bytes32[] memory hashes) internal { for (uint256 i = 0; i < ids.length; ) { _storeHash(domain, ids[i], hashes[i]); unchecked { ++i; } } } function _storeHash(uint256 domain, uint256 id, bytes32 hash) internal { bytes32 currentHash = _hashes[domain][id]; if (currentHash != hash) { _hashes[domain][id] = hash; emit HashStored(id, hash); } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { IAxelarGateway } from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol"; import { IAxelarGasService } from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol"; import { Reporter } from "../Reporter.sol"; contract AxelarReporter is Reporter, Ownable { using Strings for uint256; string public constant PROVIDER = "axelar"; bytes32 private constant NULL_STRING = keccak256(""); IAxelarGateway public immutable AXELAR_GATEWAY; IAxelarGasService public immutable AXELAR_GAS_SERVICE; mapping(uint256 => string) public chainNames; error ChainIdNotSupported(uint256 chainId); event ChainNameSet(uint256 indexed chainId, string indexed chainName); constructor( address headerStorage, address yaho, address axelarGateway, address axelarGasService ) Reporter(headerStorage, yaho) { AXELAR_GATEWAY = IAxelarGateway(axelarGateway); AXELAR_GAS_SERVICE = IAxelarGasService(axelarGasService); } function setChainNameByChainId(uint256 chainId, string calldata chainName) external onlyOwner { chainNames[chainId] = chainName; emit ChainNameSet(chainId, chainName); } function _dispatch( uint256 targetChainId, address adapter, uint256[] memory ids, bytes32[] memory hashes ) internal override returns (bytes32) { string memory targetChainName = chainNames[targetChainId]; if (keccak256(abi.encode(targetChainName)) == NULL_STRING) revert ChainIdNotSupported(targetChainId); string memory sAdapter = uint256(uint160(adapter)).toHexString(20); bytes memory payload = abi.encode(ids, hashes); if (msg.value > 0) { AXELAR_GAS_SERVICE.payNativeGasForContractCall{ value: msg.value }( address(this), targetChainName, sAdapter, payload, msg.sender ); } AXELAR_GATEWAY.callContract(targetChainName, sAdapter, payload); return bytes32(0); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { RLPReader } from "solidity-rlp/contracts/RLPReader.sol"; import { Adapter } from "./Adapter.sol"; import { IBlockHashAdapter } from "../interfaces/IBlockHashAdapter.sol"; abstract contract BlockHashAdapter is IBlockHashAdapter, Adapter { using RLPReader for RLPReader.RLPItem; /// @inheritdoc IBlockHashAdapter function proveAncestralBlockHashes(uint256 chainId, bytes[] memory blockHeaders) external { for (uint256 i = 0; i < blockHeaders.length; i++) { RLPReader.RLPItem memory blockHeaderRLP = RLPReader.toRlpItem(blockHeaders[i]); if (!blockHeaderRLP.isList()) revert InvalidBlockHeaderRLP(); RLPReader.RLPItem[] memory blockHeaderContent = blockHeaderRLP.toList(); // A block header should have between 15 and 17 elements (baseFee and withdrawalsRoot have been added later) if (blockHeaderContent.length < 15 || blockHeaderContent.length > 17) revert InvalidBlockHeaderLength(blockHeaderContent.length); bytes32 blockParent = bytes32(blockHeaderContent[0].toUint()); uint256 blockNumber = uint256(blockHeaderContent[8].toUint()); bytes32 blockHash = keccak256(blockHeaders[i]); bytes32 storedBlockHash = getHash(chainId, blockNumber); if (blockHash != storedBlockHash) revert ConflictingBlockHeader(blockNumber, blockHash, storedBlockHash); _storeHash(chainId, blockNumber - 1, blockParent); } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { IXReceiver } from "@connext/interfaces/core/IXReceiver.sol"; import { BlockHashAdapter } from "../BlockHashAdapter.sol"; contract ConnextAdapter is BlockHashAdapter, Ownable, IXReceiver { string public constant PROVIDER = "connext"; address public immutable CONNEXT; mapping(uint32 => address) public enabledReporters; mapping(uint32 => uint256) public chainIds; error UnauthorizedConnextReceive(); event ReporterSet(uint256 indexed chainId, uint32 indexed domainId, address indexed reporter); constructor(address connext) { CONNEXT = connext; } function setReporterByChain(uint256 chainId, uint32 domainId, address reporter) external onlyOwner { enabledReporters[domainId] = reporter; chainIds[domainId] = chainId; emit ReporterSet(chainId, domainId, reporter); } function xReceive( bytes32 /* transferId_ */, uint256 /* amount_ */, address /* asset_ */, address originSender, uint32 origin, bytes memory callData ) external returns (bytes memory) { if (msg.sender != CONNEXT || enabledReporters[origin] != originSender) revert UnauthorizedConnextReceive(); uint256 sourceChainId = chainIds[origin]; (uint256[] memory ids, bytes32[] memory hashes) = abi.decode(callData, (uint256[], bytes32[])); _storeHashes(sourceChainId, ids, hashes); return ""; } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { IConnext } from "@connext/interfaces/core/IConnext.sol"; import { Reporter } from "../Reporter.sol"; contract ConnextReporter is Reporter, Ownable { string public constant PROVIDER = "connext"; IConnext public immutable CONNEXT; mapping(uint256 => uint32) public domainIds; error DomainIdNotAvailable(); event DomainIdSet(uint256 indexed chainId, uint32 indexed domainId); event ConnextTransfer(bytes32 transferId); constructor(address headerStorage, address yaho, address connext) Reporter(headerStorage, yaho) { CONNEXT = IConnext(connext); } function setDomainIdByChainId(uint256 chainId, uint32 domainId) external onlyOwner { domainIds[chainId] = domainId; emit DomainIdSet(chainId, domainId); } function _dispatch( uint256 targetChainId, address adapter, uint256[] memory ids, bytes32[] memory hashes ) internal override returns (bytes32) { uint32 targetDomainId = domainIds[targetChainId]; if (targetDomainId == 0) revert DomainIdNotAvailable(); bytes memory payload = abi.encode(ids, hashes); bytes32 transferId = CONNEXT.xcall{ value: msg.value }( targetDomainId, // _destination: Domain ID of the destination chain adapter, // _to: address of the target contract address(0), // _asset: use address zero for 0-value transfers msg.sender, // _delegate: address that can revert or forceLocal on destination 0, // _amount: 0 because no funds are being transferred 0, // _slippage: can be anything between 0-10000 because no funds are being transferred payload // _callData: the encoded calldata to send ); emit ConnextTransfer(transferId); return bytes32(0); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { ILightClient, LightClientUpdate } from "./interfaces/IDendrETH.sol"; import { SSZ } from "../Telepathy/libraries/SimpleSerialize.sol"; import { BlockHashAdapter } from "../BlockHashAdapter.sol"; contract DendrETHAdapter is BlockHashAdapter { uint256 public immutable SOURCE_CHAIN_ID; address public immutable DENDRETH; error InvalidUpdate(); error BlockHeaderNotAvailable(uint256 slot); error InvalidBlockNumberProof(); error InvalidBlockHashProof(); constructor(uint256 sourceChainId, address dendreth) { SOURCE_CHAIN_ID = sourceChainId; DENDRETH = dendreth; } /// @notice Stores the block header for a given block only if it exists // in the DendrETH Light Client for the SOURCE_CHAIN_ID. function storeBlockHeader( uint64 slot, uint256 blockNumber, bytes32[] calldata blockNumberProof, bytes32 blockHash, bytes32[] calldata blockHashProof ) external { ILightClient lightClient = ILightClient(DENDRETH); uint256 currentIndex = lightClient.currentIndex(); uint256 i = currentIndex; bool found = false; do { if (slot == lightClient.optimisticSlots(i)) { found = true; break; } if (i == 0) { i = 32; } i--; } while (i != currentIndex); if (!found) { revert BlockHeaderNotAvailable(slot); } bytes32 blockHeaderRoot = lightClient.optimisticHeaders(i); if (!SSZ.verifyBlockNumber(blockNumber, blockNumberProof, blockHeaderRoot)) { revert InvalidBlockNumberProof(); } if (!SSZ.verifyBlockHash(blockHash, blockHashProof, blockHeaderRoot)) { revert InvalidBlockHashProof(); } _storeHash(SOURCE_CHAIN_ID, blockNumber, blockHash); } /// @notice Updates DendrETH Light client and stores the given block // for the update function storeBlockHeader( uint64 slot, uint256 blockNumber, bytes32[] calldata blockNumberProof, bytes32 blockHash, bytes32[] calldata blockHashProof, LightClientUpdate calldata update ) external { ILightClient lightClient = ILightClient(DENDRETH); lightClient.light_client_update(update); if (lightClient.optimisticHeaderSlot() != slot) { revert InvalidUpdate(); } bytes32 blockHeaderRoot = lightClient.optimisticHeaderRoot(); if (!SSZ.verifyBlockNumber(blockNumber, blockNumberProof, blockHeaderRoot)) { revert InvalidBlockNumberProof(); } if (!SSZ.verifyBlockHash(blockHash, blockHashProof, blockHeaderRoot)) { revert InvalidBlockHashProof(); } _storeHash(SOURCE_CHAIN_ID, blockNumber, blockHash); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.20; struct LightClientUpdate { bytes32 attestedHeaderRoot; uint256 attestedHeaderSlot; bytes32 finalizedHeaderRoot; bytes32 finalizedExecutionStateRoot; uint256[2] a; uint256[2][2] b; uint256[2] c; } interface ILightClient { function currentIndex() external view returns (uint256); function optimisticHeaders(uint256 index) external view returns (bytes32); function optimisticHeaderRoot() external view returns (bytes32); function optimisticSlots(uint256 index) external view returns (uint256); function optimisticHeaderSlot() external view returns (uint256); function light_client_update(LightClientUpdate calldata update) external; }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { IMailbox } from "@hyperlane-xyz/core/contracts/interfaces/IMailbox.sol"; import { TypeCasts } from "@hyperlane-xyz/core/contracts/libs/TypeCasts.sol"; import { Reporter } from "../Reporter.sol"; contract HyperlaneReporter is Reporter, Ownable { using TypeCasts for address; string public constant PROVIDER = "hyperlane"; IMailbox public immutable HYPERLANE_MAILBOX; mapping(uint256 => uint32) public domains; error DomainNotAvailable(); event DomainSet(uint256 indexed chainId, uint32 indexed domain); constructor(address headerStorage, address yaho, address hyperlaneMailbox) Reporter(headerStorage, yaho) { HYPERLANE_MAILBOX = IMailbox(hyperlaneMailbox); } function setDomainByChainId(uint256 chainId, uint32 domain) external onlyOwner { domains[chainId] = domain; emit DomainSet(chainId, domain); } function _dispatch( uint256 targetChainId, address adapter, uint256[] memory ids, bytes32[] memory hashes ) internal override returns (bytes32) { uint32 targetDomain = domains[targetChainId]; if (targetDomain == 0) revert DomainNotAvailable(); bytes memory payload = abi.encode(ids, hashes); HYPERLANE_MAILBOX.dispatch{ value: msg.value }(targetDomain, adapter.addressToBytes32(), payload); return bytes32(0); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { IERC777Recipient } from "@openzeppelin/contracts/interfaces/IERC777Recipient.sol"; import { IERC1820RegistryUpgradeable } from "@openzeppelin/contracts-upgradeable/interfaces/IERC1820RegistryUpgradeable.sol"; import { BlockHashAdapter } from "../BlockHashAdapter.sol"; contract PNetworkAdapter is BlockHashAdapter, Ownable { string public constant PROVIDER = "pnetwork"; address public immutable VAULT; address public immutable TOKEN; IERC1820RegistryUpgradeable private constant ERC1820 = IERC1820RegistryUpgradeable(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); bytes32 private constant TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); mapping(bytes4 => address) public enabledReporters; mapping(bytes4 => uint256) public chainIds; error InvalidSender(address sender, address expected); error InvalidToken(address token, address expected); error UnauthorizedPNetworkReceive(); event ReporterSet(uint256 indexed chainId, bytes4 indexed networkId, address indexed reporter); modifier onlySupportedToken(address _tokenAddress) { if (_tokenAddress != TOKEN) revert InvalidToken(_tokenAddress, TOKEN); _; } constructor(address pNetworkVault, address pNetworkToken) { VAULT = pNetworkVault; TOKEN = pNetworkToken; ERC1820.setInterfaceImplementer(address(this), TOKENS_RECIPIENT_INTERFACE_HASH, address(this)); } // Implement the ERC777TokensRecipient interface function tokensReceived( address, address from, address, uint256, bytes calldata data, bytes calldata ) external onlySupportedToken(msg.sender) { if (from != VAULT) revert InvalidSender(from, VAULT); (, bytes memory userData, bytes4 networkId, address sender) = abi.decode( data, (bytes1, bytes, bytes4, address) ); if (enabledReporters[networkId] != sender) revert UnauthorizedPNetworkReceive(); (uint256[] memory ids, bytes32[] memory hashes) = abi.decode(userData, (uint256[], bytes32[])); _storeHashes(chainIds[networkId], ids, hashes); } function setReporterByChain(uint256 chainId, bytes4 networkId, address reporter) external onlyOwner { enabledReporters[networkId] = reporter; chainIds[networkId] = chainId; emit ReporterSet(chainId, networkId, reporter); } }
// SPDX-License-Identifier: MIT // NOTE: This special version of the pTokens-erc20-vault is for ETH mainnet, and includes custom // logic to handle ETHPNT<->PNT fungibility, as well as custom logic to handle GALA tokens after // they upgraded from v1 to v2. pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC777/IERC777Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC777/IERC777RecipientUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/introspection/IERC1820RegistryUpgradeable.sol"; contract MockVault is Initializable, IERC777RecipientUpgradeable { using SafeERC20Upgradeable for IERC20Upgradeable; using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; IERC1820RegistryUpgradeable private constant _erc1820 = IERC1820RegistryUpgradeable(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); bytes32 private constant TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); bytes32 private constant Erc777Token_INTERFACE_HASH = keccak256("ERC777Token"); EnumerableSetUpgradeable.AddressSet private supportedTokens; bytes4 public ORIGIN_CHAIN_ID; event PegIn( address _tokenAddress, address _tokenSender, uint256 _tokenAmount, string _destinationAddress, bytes _userData, bytes4 _originChainId, bytes4 _destinationChainId ); function initialize(address[] memory _tokensToSupport, bytes4 _originChainId) public initializer { for (uint256 i = 0; i < _tokensToSupport.length; i++) { supportedTokens.add(_tokensToSupport[i]); } _erc1820.setInterfaceImplementer(address(this), TOKENS_RECIPIENT_INTERFACE_HASH, address(this)); ORIGIN_CHAIN_ID = _originChainId; } modifier onlySupportedTokens(address _tokenAddress) { require(supportedTokens.contains(_tokenAddress), "Token at supplied address is NOT supported!"); _; } function pegIn( uint256 _tokenAmount, address _tokenAddress, string calldata _destinationAddress, bytes4 _destinationChainId ) external returns (bool) { return pegIn(_tokenAmount, _tokenAddress, _destinationAddress, "", _destinationChainId); } function pegIn( uint256 _tokenAmount, address _tokenAddress, string memory _destinationAddress, bytes memory _userData, bytes4 _destinationChainId ) public onlySupportedTokens(_tokenAddress) returns (bool) { require(_tokenAmount > 0, "Token amount must be greater than zero!"); IERC20Upgradeable(_tokenAddress).safeTransferFrom(msg.sender, address(this), _tokenAmount); require(_tokenAddress != address(0), "`_tokenAddress` is set to zero address!"); emit PegIn( _tokenAddress, msg.sender, _tokenAmount, _destinationAddress, _userData, ORIGIN_CHAIN_ID, _destinationChainId ); return true; } /** * @dev Implementation of IERC777Recipient. */ function tokensReceived( address /*operator*/, address from, address to, uint256 amount, bytes calldata userData, bytes calldata /*operatorData*/ ) external override onlySupportedTokens(msg.sender) { require(to == address(this), "Token receiver is not this contract"); if (userData.length > 0) { require(amount > 0, "Token amount must be greater than zero!"); (bytes32 tag, string memory _destinationAddress, bytes4 _destinationChainId) = abi.decode( userData, (bytes32, string, bytes4) ); require(tag == keccak256("ERC777-pegIn"), "Invalid tag for automatic pegIn on ERC777 send"); emit PegIn(msg.sender, from, amount, _destinationAddress, userData, ORIGIN_CHAIN_ID, _destinationChainId); } } function pegOut( address payable _tokenRecipient, address _tokenAddress, uint256 _tokenAmount, bytes calldata _userData ) external returns (bool success) { return pegOutTokens(_tokenAddress, _tokenRecipient, _tokenAmount, _userData); } function pegOutTokens( address _tokenAddress, address _tokenRecipient, uint256 _tokenAmount, bytes memory _userData ) internal returns (bool success) { if (tokenIsErc777(_tokenAddress)) { // NOTE: This is an ERC777 token, so let's use its `send` function so that hooks are called... IERC777Upgradeable(_tokenAddress).send(_tokenRecipient, _tokenAmount, _userData); } else { // NOTE: Otherwise, we use standard ERC20 transfer function instead. IERC20Upgradeable(_tokenAddress).safeTransfer(_tokenRecipient, _tokenAmount); } return true; } function tokenIsErc777(address _tokenAddress) internal view returns (bool) { return _erc1820.getInterfaceImplementer(_tokenAddress, Erc777Token_INTERFACE_HASH) != address(0); } receive() external payable {} function changeOriginChainId(bytes4 _newOriginChainId) public returns (bool success) { ORIGIN_CHAIN_ID = _newOriginChainId; return true; } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { IHeaderStorage } from "../interfaces/IHeaderStorage.sol"; import { IReporter } from "../interfaces/IReporter.sol"; import { IAdapter } from "../interfaces/IAdapter.sol"; abstract contract Reporter is IReporter { address public immutable HEADER_STORAGE; address public immutable YAHO; modifier onlyYaho() { if (msg.sender != YAHO) revert NotYaho(msg.sender, YAHO); _; } constructor(address headerStorage, address yaho) { HEADER_STORAGE = headerStorage; YAHO = yaho; } /// @inheritdoc IReporter function dispatchBlocks( uint256 targetChainId, IAdapter adapter, uint256[] memory blockNumbers ) external payable returns (bytes32) { bytes32[] memory blockHeaders = IHeaderStorage(HEADER_STORAGE).storeBlockHeaders(blockNumbers); for (uint256 i = 0; i < blockNumbers.length; ) { emit BlockDispatched(targetChainId, adapter, blockNumbers[i], blockHeaders[i]); unchecked { ++i; } } return _dispatch(targetChainId, address(adapter), blockNumbers, blockHeaders); } /// @inheritdoc IReporter function dispatchMessages( uint256 targetChainId, IAdapter adapter, uint256[] memory messageIds, bytes32[] memory messageHashes ) external payable onlyYaho returns (bytes32) { for (uint256 i = 0; i < messageIds.length; ) { emit MessageDispatched(targetChainId, adapter, messageIds[i], messageHashes[i]); unchecked { ++i; } } return _dispatch(targetChainId, address(adapter), messageIds, messageHashes); } function _dispatch( uint256 targetChainId, address adapter, uint256[] memory ids, bytes32[] memory hashes ) internal virtual returns (bytes32); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; library SSZ { // G-indicies for the BeaconBlockHeader -> bodyRoot -> executionPayload -> {blockNumber, blockHash} uint256 internal constant EXECUTION_PAYLOAD_BLOCK_NUMBER_INDEX = 3222; uint256 internal constant EXECUTION_PAYLOAD_BLOCK_HASH_INDEX = 3228; function toLittleEndian(uint256 _v) internal pure returns (bytes32) { _v = ((_v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) | ((_v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8); _v = ((_v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) | ((_v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16); _v = ((_v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) | ((_v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32); _v = ((_v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) | ((_v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64); _v = (_v >> 128) | (_v << 128); return bytes32(_v); } function restoreMerkleRoot( bytes32 _leaf, uint256 _index, bytes32[] memory _branch ) internal pure returns (bytes32) { require(2 ** (_branch.length + 1) > _index, "incorrect branch length or index size"); bytes32 value = _leaf; uint256 i = 0; while (_index != 1) { if (_index % 2 == 1) { value = sha256(bytes.concat(_branch[i], value)); } else { value = sha256(bytes.concat(value, _branch[i])); } _index /= 2; i++; } return value; } function isValidMerkleBranch( bytes32 _leaf, uint256 _index, bytes32[] memory _branch, bytes32 _root ) internal pure returns (bool) { bytes32 restoredMerkleRoot = restoreMerkleRoot(_leaf, _index, _branch); return _root == restoredMerkleRoot; } function verifyBlockNumber( uint256 _blockNumber, bytes32[] memory _blockNumberProof, bytes32 _headerRoot ) internal pure returns (bool) { return isValidMerkleBranch( toLittleEndian(_blockNumber), EXECUTION_PAYLOAD_BLOCK_NUMBER_INDEX, _blockNumberProof, _headerRoot ); } function verifyBlockHash( bytes32 _blockHash, bytes32[] memory _blockHashProof, bytes32 _headerRoot ) internal pure returns (bool) { return isValidMerkleBranch(_blockHash, EXECUTION_PAYLOAD_BLOCK_HASH_INDEX, _blockHashProof, _headerRoot); } }
/* ███▄▄▄ ,▄▄███▄ ████▀` ,╓▄▄▄████████████▄ ███▌ ,╓▄▄▄▄█████████▀▀▀▀▀▀╙└` ███▌ ▀▀▀▀▀▀▀▀▀▀╙└└- ████L ███▌ ████` ╓██▄ ███▌ ╓▄ ╓╓╓╓╓╓╓╓╓╓╓████▄╓╓╓╓╓╓╓╓╓╓╓╓╓╓▄███████▄ ███▌ ▄█████▄ ▀▀▀▀▀▀▀▀▀▀████▀▀▀▀▀▀██▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ███████████████████████_ ▄███▀ ██µ ▐███▌ ,███▀ ▀██µ ████▌ ▄███▌, ▄████▄ ▐████▌ ▄██▀████▀▀▀▀▀▀▀▀▀▀█████▀███▄ ,█████▌ ,▄██▀_ ▓███ ▐███_ ▀████▄▄ ██████▌, ▄██▀_ ▓███ ▐███_ ▀███████▄- ███▀███▌▀███▄ ╙" ▓███▄▄▄▄▄▄▄▄▄▄▄███_ `▀███└ ▄██^ ███▌ ^████▄ ▓███▀▀▀▀▀▀▀▀▀▀▀███_ ` ▄██_ ███▌ ╙███ ▓██▀ └▀▀_ ▄, ██▀ ███▌ ▀└ ▐███▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄████▄µ ██^ ███▌ ▐███▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀██████▀ ╓█▀ ███▌ ▐███⌐ µ ╓ ▐███ ▀ ███▌ ▐███⌐ ███▄▄▄▄▄▄▄████▄ ▐███ ███▌ ▐███⌐ ████▀▀▀▀▀▀▀████▀ ▐███ ███▌ ▐███⌐ ███▌ J███M ▐███ ███▌ ▐███⌐ ███▌ J███M ▐███ ███▌ ▐███⌐ ████▄▄▄▄▄▄████M ▐███ ███▌ ▐███⌐ ███▌ ▐███M ▐███ ███▌ ▐███⌐ ███▌ ▀▀_ ████ ███▌ ▐███⌐ ▀▀_ ▀▀▀███████ ███^ ▐███_ ▐██▀▀ Made with ❤️ by Gnosis Guild */ // SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { IAdapter } from "./interfaces/IAdapter.sol"; import { IHashi } from "./interfaces/IHashi.sol"; contract Hashi is IHashi { /// @inheritdoc IHashi function checkHashWithThresholdFromAdapters( uint256 domain, uint256 id, uint256 threshold, IAdapter[] calldata adapters ) external view returns (bool) { if (threshold > adapters.length || threshold == 0) revert InvalidThreshold(threshold, adapters.length); bytes32[] memory hashes = getHashesFromAdapters(domain, id, adapters); for (uint256 i = 0; i < hashes.length; ) { if (i > hashes.length - threshold) break; bytes32 baseHash = hashes[i]; if (baseHash == bytes32(0)) { unchecked { ++i; } continue; } uint256 num = 0; for (uint256 j = i; j < hashes.length; ) { if (baseHash == hashes[j]) { unchecked { ++num; } if (num == threshold) return true; } unchecked { ++j; } } unchecked { ++i; } } return false; } /// @inheritdoc IHashi function getHashFromAdapter(uint256 domain, uint256 id, IAdapter adapter) external view returns (bytes32) { return adapter.getHash(domain, id); } /// @inheritdoc IHashi function getHashesFromAdapters( uint256 domain, uint256 id, IAdapter[] calldata adapters ) public view returns (bytes32[] memory) { if (adapters.length == 0) revert NoAdaptersGiven(); bytes32[] memory hashes = new bytes32[](adapters.length); for (uint256 i = 0; i < adapters.length; ) { hashes[i] = adapters[i].getHash(domain, id); unchecked { ++i; } } return hashes; } /// @inheritdoc IHashi function getHash(uint256 domain, uint256 id, IAdapter[] calldata adapters) external view returns (bytes32 hash) { if (adapters.length == 0) revert NoAdaptersGiven(); bytes32[] memory hashes = getHashesFromAdapters(domain, id, adapters); hash = hashes[0]; if (hash == bytes32(0)) revert HashNotAvailableInAdapter(adapters[0]); for (uint256 i = 1; i < hashes.length; ) { if (hashes[i] == bytes32(0)) revert HashNotAvailableInAdapter(adapters[i]); if (hash != hashes[i]) revert AdaptersDisagree(adapters[i - 1], adapters[i]); unchecked { ++i; } } } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; /** * @title IAdapter */ interface IAdapter { error ConflictingBlockHeader(uint256 blockNumber, bytes32 blockHash, bytes32 storedBlockHash); error InvalidBlockHeaderLength(uint256 length); error InvalidBlockHeaderRLP(); /** * @dev Emitted when a hash is stored. * @param id - The ID of the stored hash. * @param hash - The stored hash as bytes32 values. */ event HashStored(uint256 indexed id, bytes32 indexed hash); /** * @dev Returns the hash for a given ID. * @param domain - Identifier for the domain to query. * @param id - Identifier for the ID to query. * @return hash Bytes32 hash for the given ID on the given domain. * @notice MUST return bytes32(0) if the hash is not present. */ function getHash(uint256 domain, uint256 id) external view returns (bytes32 hash); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; import { IAdapter } from "./IAdapter.sol"; /** * @title IBlockHashAdapter */ interface IBlockHashAdapter is IAdapter { /** * @dev Proves and stores valid ancestral block hashes for a given chain ID. * @param chainId - The ID of the chain to prove block hashes for. * @param blockHeaders - The RLP encoded block headers to prove the hashes for. * @notice Block headers should be ordered by descending block number and should start with a known block header. */ function proveAncestralBlockHashes(uint256 chainId, bytes[] memory blockHeaders) external; }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; import { IAdapter } from "./IAdapter.sol"; import { IHashi } from "./IHashi.sol"; import { IShuSho } from "./IShuSho.sol"; /** * @title IGiriGiriBashi */ interface IGiriGiriBashi is IShuSho { struct Challenge { address payable challenger; // account that raised the challenge. uint256 timestamp; // timestamp when the challenge was created. uint256 bond; // bond paid by the challenger. } struct Settings { bool quarantined; // whether or not the adapter has been quarantined. uint256 minimumBond; // amount that must be bonded alongside a challenge. uint256 startId; // earliest id that the adapter could have stored. uint256 idDepth; // how far behind the current head can this adapter safely report. 0 equals infinite. uint256 timeout; // grace period in which the adapter must report on an in-range id after being challenged. } error AdaptersCannotContainChallengedAdapter(IAdapter[] adapters, IAdapter adapter); error AdapterHasNotYetTimedOut(IAdapter adapter); error AdapterNotQuarantined(IAdapter adapter); error AlreadyQuarantined(IAdapter adapter); error CannotProveNoConfidence(uint256 domain, uint256 id, IAdapter[] adapters); error ChallengeNotFound(bytes32 challengeId, uint256 domain, uint256 id, IAdapter adapter); error ChallengeRangeAlreadySet(uint256 domain); error CountMustBeZero(uint256 domain); error DuplicateChallenge(bytes32 challengeId, uint256 domain, uint256 id, IAdapter adapter); error NoConfidenceRequired(); error NotEnoughValue(IAdapter adapter, uint256 value); error OutOfRange(IAdapter adapter, uint256 id); error UnequalArrayLengths(); /** * @dev Emitted when the bond recipient address is set. * @param bondRecipient - The new bond recipient address as an Ethereum address. */ event BondRecipientSet(address payable bondRecipient); /** * @dev Emitted when a challenge is created. * @param challengeId - The unique identifier for the challenge. * @param domain - The domain associated with the challenge. * @param id - The identifier associated with the challenge. * @param adapter - The adapter address associated with the challenge. * @param challenger - The address of the challenger. * @param timestamp - The timestamp when the challenge was created. * @param bond - The bond amount associated with the challenge. */ event ChallengeCreated( bytes32 challengeId, uint256 indexed domain, uint256 id, IAdapter indexed adapter, address indexed challenger, uint256 timestamp, uint256 bond ); /** * @dev Emitted when the challenge range is updated. * @param domain - The domain associated with the updated challenge range. * @param range - The new challenge range as a Uint256 identifier. */ event ChallengeRangeUpdated(uint256 domain, uint256 range); /** * @dev Emitted when a challenge is resolved. * @param challengeId - The unique identifier for the resolved challenge. * @param domain - The domain associated with the resolved challenge. * @param id - The identifier associated with the resolved challenge. * @param adapter - The adapter address associated with the resolved challenge. * @param challenger - The address of the challenger. * @param bond - The bond amount associated with the resolved challenge. * @param challengeSuccessful - A boolean indicating whether the challenge was successful. */ event ChallengeResolved( bytes32 challengeId, uint256 indexed domain, uint256 id, IAdapter indexed adapter, address indexed challenger, uint256 bond, bool challengeSuccessful ); /** * @dev Emitted when a new head is updated. * @param domain - The domain associated with the new head. * @param head - The new head as a Uint256 identifier. */ event NewHead(uint256 domain, uint256 head); /** * @dev Emitted when a declaration of no confidence is made for a specific domain. * @param domain - The domain associated with the declaration. */ event NoConfidenceDeclared(uint256 domain); /** * @dev Emitted when settings are initialized for a specific domain and adapter. * @param domain - The domain associated with the initialized settings. * @param adapter - The adapter address associated with the initialized settings. * @param settings - The initialized settings object. */ event SettingsInitialized(uint256 domain, IAdapter adapter, Settings settings); /** * @dev Challenges the adapter to provide a response. If the adapter fails, it can be quarantined. * @param domain - The Uint256 identifier for the domain. * @param id - The Uint256 identifier for the challenge. * @param adapter - The address of the adapter to challenge. * @notice Caller must pay a minimum bond to issue the challenge. This bond should be high enough to cover the gas costs for successfully completing the challenge. */ function challengeAdapter(uint256 domain, uint256 id, IAdapter adapter) external payable; /** * @dev Show that enough adapters disagree that they could not make a threshold if the remainder all agree with one. * @param domain - The Uint256 identifier for the domain. * @param id - The Uint256 identifier. * @param adapters - An array of adapter instances. */ function declareNoConfidence(uint256 domain, uint256 id, IAdapter[] memory adapters) external; /** * @dev Disables a set of adapters for a given domain. * @param domain - The Uint256 identifier for the domain. * @param adapters - An array of adapter instances to be disabled. */ function disableAdapters(uint256 domain, IAdapter[] memory adapters) external; /** * @dev Enables a set of adapters for a given domain with specific settings. * @param domain - The Uint256 identifier for the domain. * @param adapters - An array of adapter instances. * @param settings - An array of settings, corresponding to each adapter. */ function enableAdapters(uint256 domain, IAdapter[] memory adapters, Settings[] memory settings) external; /** * @dev Get the current challenge given a challengeId. * @param challengeId - The Bytes32 identifier for the challenge. * @return challenge - Challenge indicating the challenge parameters. */ function getChallenge(bytes32 challengeId) external view returns (Challenge memory); /** * @dev Gets the challenge ID for a given domain, ID, and adapter. * @param domain - The Uint256 identifier for the domain. * @param id - The Uint256 identifier. * @param adapter - The adapter instance. * @return The computed challenge ID as a bytes32 hash. */ function getChallengeId(uint256 domain, uint256 id, IAdapter adapter) external pure returns (bytes32); /** * @dev Get how far beyond the current highestId can be challenged. * @param domain - The Uint256 identifier for the domain. * @return range - Uint256 indicating the challenge range. */ function getChallengeRange(uint256 domain) external view returns (uint256); /** * @dev Returns the hash agreed upon by a threshold of the enabled adapters. * @param domain - Uint256 identifier for the domain to query. * @param id - Uint256 identifier to query. * @return hash - Bytes32 hash agreed upon by a threshold of the adapters for the given domain. * @notice Reverts if no threshold is not reached. * @notice Reverts if no adapters are set for the given domain. */ function getThresholdHash(uint256 domain, uint256 id) external returns (bytes32); /** * @dev Returns the hash unanimously agreed upon by ALL of the enabled adapters. * @param domain - Uint256 identifier for the domain to query. * @param id - Uint256 identifier to query. * @return hash - Bytes32 hash agreed upon by the adapters for the given domain. * @notice Reverts if adapters disagree. * @notice Revert if the adapters do not yet have the hash for the given ID. * @notice Reverts if no adapters are set for the given domain. */ function getUnanimousHash(uint256 domain, uint256 id) external returns (bytes32); /** * @dev Returns the hash unanimously agreed upon by all of the given adapters. * @param domain - Uint256 identifier for the domain to query. * @param adapters - Array of adapter addresses to query. * @param id - Uint256 identifier to query. * @return hash - Bytes32 hash agreed upon by the adapters for the given domain. * @notice Adapters must be in numerical order from smallest to largest and contain no duplicates. * @notice Reverts if adapters are out of order or contain duplicates. * @notice Reverts if adapters disagree. * @notice Revert if the adapters do not yet have the hash for the given ID. * @notice Reverts if no adapters are set for the given domain. */ function getHash(uint256 domain, uint256 id, IAdapter[] memory adapters) external returns (bytes32); /** * @dev Returns the highest id reported for a given id * @param domain - Uint256 identifier for the domain to query. * @return id - Uint256 indicating the highest id reported. */ function getHead(uint256 domain) external view returns (uint256); /** * @dev Get the current settings for a given adapter. * @param domain - Uint256 identifier for the domain to query. * @param adapter - The adapter. * @return settings - The Settings for the given adapter. */ function getSettings(uint256 domain, IAdapter adapter) external view returns (Settings memory); /** * @dev Replaces the quarantined adapters for a given domain with new adapters and settings. * @param domain - The Uint256 identifier for the domain. * @param currentAdapters - An array of current adapter instances to be replaced. * @param newAdapters - An array of new adapter instances to replace the current ones. * @param settings - An array of settings corresponding to the new adapters. */ function replaceQuarantinedAdapters( uint256 domain, IAdapter[] memory currentAdapters, IAdapter[] memory newAdapters, Settings[] memory settings ) external; /** * @dev Resolves a challenge by comparing results from a specific adapter with others. * @param domain - The Uint256 identifier for the domain. * @param id - The Uint256 identifier. * @param adapter - The adapter instance for comparison. * @param adapters - An array of adapter instances for comparison. * @return A boolean indicating the success of the challenge resolution. */ function resolveChallenge( uint256 domain, uint256 id, IAdapter adapter, IAdapter[] memory adapters ) external returns (bool); /** * @dev Sets the bond recipient address for payments. * @param bondRecipient - The address where bond payments should be sent. */ function setBondRecipient(address payable bondRecipient) external; /** * @dev Sets the challenge range for a specific domain. * @param domain - The Uint256 identifier for the domain. * @param range - The Uint256 range to set for the given domain. */ function setChallengeRange(uint256 domain, uint256 range) external; /** * @dev Sets the threshold for a specific domain. * @param domain - The Uint256 identifier for the domain. * @param threshold - The Uint256 threshold to set for the given domain. */ function setThreshold(uint256 domain, uint256 threshold) external; }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; import { IAdapter } from "./IAdapter.sol"; /** * @title IHashi */ interface IHashi { error AdaptersDisagree(IAdapter adapterOne, IAdapter adapterTwo); error HashNotAvailableInAdapter(IAdapter adapter); error InvalidThreshold(uint256 threshold, uint256 maxThreshold); error NoAdaptersGiven(); /** * @dev Checks whether the threshold is reached for a message given a set of adapters. * @param domain - ID of the domain to query. * @param id - ID for which to return hash. * @param threshold - Threshold to use. * @param adapters - Array of addresses for the adapters to query. * @notice If the threshold is 1, it will always return true. * @return result A boolean indicating if a threshold for a given message has been reached. */ function checkHashWithThresholdFromAdapters( uint256 domain, uint256 id, uint256 threshold, IAdapter[] calldata adapters ) external view returns (bool); /** * @dev Returns the hash stored by a given adapter for a given ID. * @param domain - ID of the domain to query. * @param id - ID for which to return a hash. * @param adapter - Address of the adapter to query. * @return hash stored by the given adapter for the given ID. */ function getHashFromAdapter(uint256 domain, uint256 id, IAdapter adapter) external view returns (bytes32); /** * @dev Returns the hashes for a given ID stored by a given set of adapters. * @param domain - The ID of the domain to query. * @param id - The ID for which to return hashes. * @param adapters - An array of addresses for the adapters to query. * @return hashes An array of hashes stored by the given adapters for the specified ID. */ function getHashesFromAdapters( uint256 domain, uint256 id, IAdapter[] calldata adapters ) external view returns (bytes32[] memory); /** * @dev Returns the hash unanimously agreed upon by a given set of adapters. * @param domain - The ID of the domain to query. * @param id - The ID for which to return a hash. * @param adapters - An array of addresses for the adapters to query. * @return hash agreed on by the given set of adapters. * @notice MUST revert if adapters disagree on the hash or if an adapter does not report. */ function getHash(uint256 domain, uint256 id, IAdapter[] calldata adapters) external view returns (bytes32); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; /** * @title IHeaderStorage */ interface IHeaderStorage { error HeaderOutOfRange(uint256 blockNumber); /** * @dev Emitted when a block header is stored. * @param blockNumber - The block number associated with the stored header. * @param blockHeader - The stored block header as a bytes32 value. */ event HeaderStored(uint256 indexed blockNumber, bytes32 indexed blockHeader); /** * @dev Retrieves the stored block header for a specific block number. * @param blockNumber - The block number as a uint256 value. * @return The block header as a bytes32 value. */ function headers(uint256 blockNumber) external view returns (bytes32); /** * @dev Stores and returns the header for the given block. * @param blockNumber - Block number. * @return blockHeader - Block header stored. * @notice Reverts if the given block header was not previously stored and is now out of range. */ function storeBlockHeader(uint256 blockNumber) external returns (bytes32); /** * @dev Stores and returns the header for an array of given blocks. * @param blockNumbers - Array of block numbers. * @return blockHeaders - Array of block headers stored. * @notice Reverts if the given block header was not previously stored and is now out of range. */ function storeBlockHeaders(uint256[] memory blockNumbers) external returns (bytes32[] memory); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; import { IAdapter } from "./IAdapter.sol"; /** * @title IJushin */ interface IJushin { /** * @dev Handles the incoming message from a specified chain. * @param messageId - The unique identifier of the message. * @param sourceChainId - The ID of the origin chain from which the message originates. * @param sender - The address of the sender of the message on the origin chain. * @param threshold - The minimum number of adapters required to have stored the same message. * @param data - The data contained in the message, in bytes. * @param adapters - An array of `IAdapter` contracts. * @return result bytes at the user's choice */ function onMessage( uint256 messageId, uint256 sourceChainId, address sender, uint256 threshold, IAdapter[] calldata adapters, bytes calldata data ) external returns (bytes memory); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; import { IReporter } from "./IReporter.sol"; import { IAdapter } from "./IAdapter.sol"; struct Message { uint256 nonce; uint256 targetChainId; uint256 threshold; address sender; address receiver; bytes data; IReporter[] reporters; IAdapter[] adapters; }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; import { Message } from "./IMessage.sol"; /** * @title IMessageHashCalculator */ interface IMessageHashCalculator { /** * @dev Calculates and returns the hash of a given message. * @param message - The `Message` structure containing various fields to be hashed. * @return hash The keccak256 hash of the message, represented as a 32-byte hexadecimal string. */ function calculateMessageHash(Message memory message) external pure returns (bytes32); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; /** * @title IMessageIdCalculator */ interface IMessageIdCalculator { /** * @dev Calculates and returns a unique identifier (ID) for a message. * * @param sourceChainId - The ID of the chain from which the message originates. * @param dispatcherAddress - The address of the dispatcher sending the message. * @param messageHash - The keccak256 hash of the message, represented as a 32-byte hexadecimal string. * @return messageId The unique identifier for the message, calculated based on the input parameters. */ function calculateMessageId( uint256 sourceChainId, address dispatcherAddress, bytes32 messageHash ) external pure returns (uint256); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; import { IAdapter } from "./IAdapter.sol"; interface IReporter { error NotYaho(address sender, address expectedYaho); /** * @dev Emitted when a block is dispatched to another chain. * @param targetChainId - The target chain's identifier associated with the dispatched block. * @param adapter - The adapter address associated with the dispatched block. * @param blockNumber - The block number associated with the dispatched block. * @param blockHeader - The dispatched block header as a bytes32 value. */ event BlockDispatched( uint256 indexed targetChainId, IAdapter adapter, uint256 indexed blockNumber, bytes32 blockHeader ); /** * @dev Emitted when a message is dispatched to another chain. * @param targetChainId - The target chain's identifier associated with the dispatched message. * @param adapter - The adapter address associated with the dispatched message. * @param messageId - The message identifier associated with the dispatched message. * @param messageHash - The dispatched message hash as a bytes32 value. */ event MessageDispatched( uint256 indexed targetChainId, IAdapter adapter, uint256 indexed messageId, bytes32 messageHash ); /** * @dev Dispatches blocks to a given adapter on the target chaib. * @param targetChainId - The target chain's Uint256 identifier. * @param adapter - The adapter instance to use. * @param blockNumbers - An array of Uint256 block numbers to dispatch. * @notice blockNumbers must include block numbers that are greater than or equal to (currentBlock - 256) due to EVM limitations. * @return result - The result returned by the adapter as bytes. */ function dispatchBlocks( uint256 targetChainId, IAdapter adapter, uint256[] memory blockNumbers ) external payable returns (bytes32); /** * @dev Dispatches messages to a target chain using the specified adapter. * @param targetChainId - The target chain's Uint256 identifier. * @param adapter - The adapter instance to use. * @param messageIds - An array of Uint256 message identifiers. * @param messageHashes - An array of bytes32 message hashes. * @notice This function can be called only by Yaho * @return result - The result returned by the adapter as bytes. */ function dispatchMessages( uint256 targetChainId, IAdapter adapter, uint256[] memory messageIds, bytes32[] memory messageHashes ) external payable returns (bytes32); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; import { IHashi } from "./IHashi.sol"; import { IAdapter } from "./IAdapter.sol"; import { IShuSho } from "./IShuSho.sol"; /** * @title IShoyuBashi */ interface IShoyuBashi is IShuSho { /** * @dev Disables the given adapters for a given domain. * @param domain - Uint256 identifier for the domain for which to set adapters. * @param adapters - Array of adapter addresses. * @notice Only callable by the owner of this contract. * @notice Reverts if adapters are out of order or contain duplicates. */ function disableAdapters(uint256 domain, IAdapter[] memory adapters) external; /** * @dev Enables the given adapters for a given domain. * @param domain - Uint256 identifier for the domain for which to set adapters. * @param adapters - Array of adapter addresses. * @param threshold - Uint256 threshold to set for the given domain. * @notice Only callable by the owner of this contract. * @notice Reverts if adapters are out of order, contain duplicates or if the threshold is not higher than half the count of the adapters */ function enableAdapters(uint256 domain, IAdapter[] memory adapters, uint256 threshold) external; /** * @dev Returns the hash unanimously agreed upon by ALL of the enabled adapters. * @param domain - Uint256 identifier for the domain to query. * @param id - Uint256 identifier to query. * @return Bytes32 hash agreed upon by the adapters for the given domain. * @notice Revert if the adapters do not yet have the hash for the given ID. * @notice Reverts if adapters disagree. * @notice Reverts if no adapters are set for the given domain. */ function getUnanimousHash(uint256 domain, uint256 id) external view returns (bytes32); /** * @dev Returns the hash agreed upon by a threshold of the enabled adapters. * @param domain - Uint256 identifier for the domain to query. * @param id - Uint256 identifier to query. * @return Bytes32 hash agreed upon by a threshold of the adapters for the given domain. * @notice Reverts if the threshold is not reached. * @notice Reverts if no adapters are set for the given domain. */ function getThresholdHash(uint256 domain, uint256 id) external view returns (bytes32); /** * @dev Returns the hash unanimously agreed upon by all of the given adapters. * @param domain - Uint256 identifier for the domain to query. * @param adapters - Array of adapter addresses to query. * @param id - Uint256 identifier to query. * @return Bytes32 hash agreed upon by the adapters for the given domain. * @notice adapters must be in numerical order from smallest to largest and contain no duplicates. * @notice Reverts if adapters are out of order or contain duplicates. * @notice Reverts if adapters disagree. * @notice Revert if the adapters do not yet have the hash for the given ID. * @notice Reverts if no adapters are set for the given domain. */ function getHash(uint256 domain, uint256 id, IAdapter[] memory adapters) external view returns (bytes32); /** * @dev Sets the threshold of adapters required for a given domain. * @param domain - Uint256 identifier for the domain for which to set the threshold. * @param threshold - Uint256 threshold to set for the given domain. * @notice Only callable by the owner of this contract. * @notice Reverts if the threshold is already set to the given value. */ function setThreshold(uint256 domain, uint256 threshold) external; /** * @dev Sets the address of the IHashi contract. * @param hashi - Address of the hashi contract. * @notice Only callable by the owner of this contract. */ function setHashi(IHashi hashi) external; }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; import { IHashi } from "./IHashi.sol"; import { IAdapter } from "./IAdapter.sol"; /** * @title IShuSho */ interface IShuSho { struct Domain { uint256 threshold; uint256 count; } struct Link { IAdapter previous; IAdapter next; } error AdapterNotEnabled(IAdapter adapter); error AdapterAlreadyEnabled(IAdapter adapter); error CountCannotBeZero(); error DuplicateHashiAddress(IHashi hashi); error DuplicateOrOutOfOrderAdapters(IAdapter adapterOne, IAdapter adapterTwo); error DuplicateThreshold(uint256 threshold); error InvalidAdapter(IAdapter adapter); error InvalidThreshold(uint256 threshold); error NoAdaptersEnabled(uint256 domain); error NoAdaptersGiven(); error ThresholdNotMet(); /** * @dev Emitted when adapters are disabled for a specific domain. * @param domain - The domain associated with the disabled adapters. * @param adapters - An array of disabled adapter addresses associated with this event. */ event AdaptersDisabled(uint256 indexed domain, IAdapter[] adapters); /** * @dev Emitted when adapters are enabled for a specific domain. * @param domain - The domain associated with the enabled adapters. * @param adapters - An array of enabled adapter addresses associated with this event. */ event AdaptersEnabled(uint256 indexed domain, IAdapter[] adapters); /** * @dev Emitted when the address of the IHashi contract is set. * @param hashi - The address of the IHashi contract associated with this event. */ event HashiSet(IHashi indexed hashi); /** * @dev Emitted when initialization occurs with the owner's address and the IHashi contract address. * @param owner - The address of the owner associated with this event. * @param hashi - The address of the IHashi contract associated with this event. */ event Init(address indexed owner, IHashi indexed hashi); /** * @dev Emitted when the threshold is set for a specific domain. * @param domain - The domain associated with the set threshold. * @param threshold - The new threshold value associated with this event. */ event ThresholdSet(uint256 domain, uint256 threshold); /** * @dev Checks the order and validity of adapters for a given domain. * @param domain - The Uint256 identifier for the domain. * @param _adapters - An array of adapter instances. */ function checkAdapterOrderAndValidity(uint256 domain, IAdapter[] memory _adapters) external view; /** * @dev Get the previous and the next adapter given a domain and an adapter. * @param domain - Uint256 identifier for the domain. * @param adapter - IAdapter value for the adapter. * @return link - The Link struct containing the previous and the next adapter. */ function getAdapterLink(uint256 domain, IAdapter adapter) external view returns (Link memory); /** * @dev Returns an array of enabled adapters for a given domain. * @param domain - Uint256 identifier for the domain for which to list adapters. * @return adapters - The adapters for a given domain. */ function getAdapters(uint256 domain) external view returns (IAdapter[] memory); /** * @dev Get the current configuration for a given domain. * @param domain - Uint256 identifier for the domain. * @return domain - The Domain struct containing the current configuration for a given domain. */ function getDomain(uint256 domain) external view returns (Domain memory); /** * @dev Returns the threshold and count for a given domain. * @param domain - Uint256 identifier for the domain. * @return threshold - Uint256 adapters threshold for the given domain. * @return count - Uint256 adapters count for the given domain. * @notice If the threshold for a domain has not been set, or is explicitly set to 0, this function will return a threshold equal to the adapters count for the given domain. */ function getThresholdAndCount(uint256 domain) external view returns (uint256, uint256); /** * @dev Returns the address of the specified Hashi. * @return hashi - The Hashi address. */ function hashi() external view returns (IHashi); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; import { IMessageHashCalculator } from "./IMessageHashCalculator.sol"; import { IMessageIdCalculator } from "./IMessageIdCalculator.sol"; import { Message } from "./IMessage.sol"; import { IReporter } from "./IReporter.sol"; import { IAdapter } from "./IAdapter.sol"; /** * @title IYaho */ interface IYaho is IMessageHashCalculator, IMessageIdCalculator { error NoMessagesGiven(); error NoMessageIdsGiven(); error NoReportersGiven(); error NoAdaptersGiven(); error UnequalArrayLengths(uint256 arrayOne, uint256 arrayTwo); error MessageHashNotFound(uint256 messageId); error InvalidMessage(Message message); error InvalidThreshold(uint256 threshold, uint256 maxThreshold); /** * @dev Emitted when a message is dispatched with its associated message ID and message struct. * @param messageId - The message ID associated with the dispatched message. * @param message - The message struct associated with this event. */ event MessageDispatched(uint256 indexed messageId, Message message); /** * @dev Dispatches a message to a specified chain with a set of validation parameters without calling the reporters. It just write in storage a commitment of message. In order to dispatch it to the reporters, you must then invoke `relayMessagesToAdapters` * @param targetChainId - The ID of the target chain to which the message is being sent. * @param threshold - The minimum number of adapters required to have stored the same message. * @param receiver - The address of the receiver on the target chain. * @param data - The data being sent in the message, represented as a byte array. * @param reporters - An array of `IReporter` contracts (not actively used in this step). * @param adapters - An array of `IAdapter` contracts (for later validation use). * @return messageId A unique identifier for the dispatched message, used for tracking and subsequent validation. * @notice If you plan to use an Adapter that does not have a corresponding Reporter (such as an adapter that uses a light client), you need to specify only the adapter and use address(0) as the reporter, since the adapter will verify the MessageDispatched event emitted by Yaho. * */ function dispatchMessage( uint256 targetChainId, uint256 threshold, address receiver, bytes calldata data, IReporter[] calldata reporters, IAdapter[] calldata adapters ) external returns (uint256); /** * @dev Dispatches a message to a specified chain with a set of validation parameters and calls the reporters. * @param targetChainId - The ID of the target chain to which the message is being sent. * @param threshold - The minimum number of adapters required to have stored the same message. * @param receiver - The address of the receiver on the target chain. * @param data - The data being sent in the message, represented as a byte array. * @param reporters - An array of `IReporter` contracts (not actively used in this step). * @param adapters - An array of `IAdapter` contracts (for later validation use). * @return (messageId, result) A unique identifier for the dispatched message and an array of byte arrays, where each element is the result of dispatching a respective message to the corresponding Reporter. * @notice If you plan to use an Adapter that does not have a corresponding Reporter (such as an adapter that uses a light client), you need to specify only the adapter and use address(0) as the reporter, since the adapter will verify the MessageDispatched event emitted by Yaho. */ function dispatchMessageToAdapters( uint256 targetChainId, uint256 threshold, address receiver, bytes calldata data, IReporter[] calldata reporters, IAdapter[] calldata adapters ) external payable returns (uint256, bytes32[] memory); /** * @dev Dispatches an array of messages to specified chains and calls the reporters. * @param targetChainId - The ID of the target chain for all messages. * @param thresholds - An array of minimum validation thresholds required for each message. * @param receivers - An array of addresses for the receivers on the target chain, one for each message. * @param data - An array of data payloads for each message, represented as byte arrays. * @param reporters - An array of `IReporter` contracts for reporting the status of each message. * @param adapters - An array of `IAdapter` contracts used for the validation of each message. * @return (messageIds, result) An array of unique identifiers for the dispatched messages and an array of bytes32 arrays, where each element is the result of dispatching a respective message to the corresponding Reporter. * @notice If you plan to use an Adapter that does not have a corresponding Reporter (such as an adapter that uses a light client), you need to specify only the adapter and use address(0) as the reporter, since the adapter will verify the MessageDispatched event emitted by Yaho. */ function dispatchMessagesToAdapters( uint256 targetChainId, uint256[] calldata thresholds, address[] calldata receivers, bytes[] calldata data, IReporter[] calldata reporters, IAdapter[] calldata adapters ) external payable returns (uint256[] memory, bytes32[] memory); /** * @dev Retrieves the hash of a pending message that was dispatched via `dispatchMessage` but has not yet been relayed to adapters using `relayingMessagesToAdapters`. * @param messageId - The unique identifier of the message for which the hash is being retrieved. * @return messageHash The hash of the pending message if it exists. */ function getPendingMessageHash(uint256 messageId) external view returns (bytes32); /** * @dev Relays an array of messages to their respective adapters. In order to be able to aggregate messages within the reporter, it's mandatory that all messages have the same targetChainId, reporters and adapters. * @param messages - An array of `Message` structures to be relayed to the adapters. * @return result An array of bytes32 arrays, where each element is the result of dispatching a respective all messages to the corresponding Reporter. */ function relayMessagesToAdapters(Message[] calldata messages) external payable returns (bytes32[] memory); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.0; import { Message } from "./IMessage.sol"; import { IMessageHashCalculator } from "./IMessageHashCalculator.sol"; import { IMessageIdCalculator } from "./IMessageIdCalculator.sol"; /** * @title IYaru */ interface IYaru is IMessageHashCalculator, IMessageIdCalculator { error CallFailed(); error InvalidToChainId(uint256 chainId, uint256 expectedChainId); error MessageIdAlreadyExecuted(uint256 messageId); error ThresholdNotMet(); /** * @dev Emitted when a message is executed with its associated message ID and message object. * @param messageId - The message ID associated with the executed message. * @param message - The message object associated with this event. */ event MessageExecuted(uint256 indexed messageId, Message message); /** * @dev Executes a batch of messages and returns the results if the threshold for a single message has been reached * @param messages - An array of `Message` structures * @return result An array of byte arrays, where each byte array is the result of executing a respective message from the input. */ function executeMessages(Message[] calldata messages) external returns (bytes[] memory); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { ShuSo } from "./ShuSo.sol"; import { IAdapter } from "../interfaces/IAdapter.sol"; import { IShoyuBashi } from "../interfaces/IShoyuBashi.sol"; import { IHashi } from "../interfaces/IHashi.sol"; contract ShoyuBashi is IShoyuBashi, ShuSo { constructor(address _owner, address _hashi) ShuSo(_owner, _hashi) {} // solhint-disable no-empty-blocks /// @inheritdoc IShoyuBashi function setThreshold(uint256 domain, uint256 threshold) external { _setThreshold(domain, threshold); } /// @inheritdoc IShoyuBashi function enableAdapters(uint256 domain, IAdapter[] memory adapters, uint256 threshold) external { _enableAdapters(domain, adapters, threshold); } /// @inheritdoc IShoyuBashi function disableAdapters(uint256 domain, IAdapter[] memory adapters) external { _disableAdapters(domain, adapters); } /// @inheritdoc IShoyuBashi function getUnanimousHash(uint256 domain, uint256 id) external view returns (bytes32) { return _getUnanimousHash(domain, id); } /// @inheritdoc IShoyuBashi function getThresholdHash(uint256 domain, uint256 id) external view returns (bytes32) { return _getThresholdHash(domain, id); } /// @inheritdoc IShoyuBashi function getHash(uint256 domain, uint256 id, IAdapter[] memory adapters) external view returns (bytes32) { return _getHash(domain, id, adapters); } /// @inheritdoc IShoyuBashi function setHashi(IHashi _hashi) external { _setHashi(_hashi); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { IAdapter } from "../interfaces/IAdapter.sol"; import { IHashi } from "../interfaces/IHashi.sol"; import { IShuSho } from "../interfaces/IShuSho.sol"; abstract contract ShuSo is IShuSho, OwnableUpgradeable { IAdapter internal constant LIST_END = IAdapter(address(0x1)); IHashi public hashi; mapping(uint256 => mapping(IAdapter => Link)) private _adapters; mapping(uint256 => Domain) private _domains; constructor(address _owner, address _hashi) { bytes memory initParams = abi.encode(_owner, _hashi); init(initParams); } function init(bytes memory initParams) public initializer { (address _owner, IHashi _hashi) = abi.decode(initParams, (address, IHashi)); __Ownable_init(); _setHashi(_hashi); transferOwnership(_owner); emit Init(_owner, _hashi); } /// @inheritdoc IShuSho function checkAdapterOrderAndValidity(uint256 domain, IAdapter[] memory adapters) public view { for (uint256 i = 0; i < adapters.length; i++) { IAdapter adapter = adapters[i]; if (i > 0 && adapter <= adapters[i - 1]) revert DuplicateOrOutOfOrderAdapters(adapter, adapters[i - 1]); if (_adapters[domain][adapter].next == IAdapter(address(0))) revert InvalidAdapter(adapter); } } /// @inheritdoc IShuSho function getAdapterLink(uint256 domain, IAdapter adapter) external view returns (Link memory) { return _adapters[domain][adapter]; } /// @inheritdoc IShuSho function getAdapters(uint256 domain) public view returns (IAdapter[] memory) { IAdapter[] memory adapters = new IAdapter[](_domains[domain].count); IAdapter currentAdapter = _adapters[domain][LIST_END].next; for (uint256 i = 0; i < adapters.length; i++) { adapters[i] = currentAdapter; currentAdapter = _adapters[domain][currentAdapter].next; } return adapters; } /// @inheritdoc IShuSho function getDomain(uint256 domain) external view returns (Domain memory) { return _domains[domain]; } /// @inheritdoc IShuSho function getThresholdAndCount(uint256 domain_) public view returns (uint256, uint256) { Domain storage domain = _domains[domain_]; uint256 threshold = domain.threshold; uint256 count = domain.count; if (threshold == 0) threshold = count; return (threshold, count); } /** * @dev Disables the given adapters for a given domain. * @param domain - Uint256 identifier for the domain for which to set adapters. * @param adapters - Array of adapter addresses. * @notice Reverts if adapters are out of order or contain duplicates. * @notice Only callable by the owner of this contract. */ function _disableAdapters(uint256 domain, IAdapter[] memory adapters) internal onlyOwner { if (_domains[domain].count == 0) revert NoAdaptersEnabled(domain); if (adapters.length == 0) revert NoAdaptersGiven(); for (uint256 i = 0; i < adapters.length; i++) { IAdapter adapter = adapters[i]; if (adapter == IAdapter(address(0)) || adapter == LIST_END) revert InvalidAdapter(adapter); Link memory current = _adapters[domain][adapter]; if (current.next == IAdapter(address(0))) revert AdapterNotEnabled(adapter); IAdapter next = current.next; IAdapter previous = current.previous; _adapters[domain][next].previous = previous; _adapters[domain][previous].next = next; delete _adapters[domain][adapter].next; delete _adapters[domain][adapter].previous; _domains[domain].count--; } emit AdaptersDisabled(domain, adapters); } /** * @dev Enables the given adapters for a given domain. * @param domain - Uint256 identifier for the domain for which to set adapters. * @param adapters - Array of adapter addresses. * @param threshold - Uint256 threshold to set for the given domain. * @notice Reverts if adapters are out of order, contain duplicates or if the threshold is not higher than half the count of the adapters * @notice Only callable by the owner of this contract. */ function _enableAdapters(uint256 domain, IAdapter[] memory adapters, uint256 threshold) internal onlyOwner { if (_adapters[domain][LIST_END].next == IAdapter(address(0))) { _adapters[domain][LIST_END].next = LIST_END; _adapters[domain][LIST_END].previous = LIST_END; } if (adapters.length == 0) revert NoAdaptersGiven(); for (uint256 i = 0; i < adapters.length; i++) { IAdapter adapter = adapters[i]; if (adapter == IAdapter(address(0)) || adapter == LIST_END) revert InvalidAdapter(adapter); if (_adapters[domain][adapter].next != IAdapter(address(0))) revert AdapterAlreadyEnabled(adapter); IAdapter previous = _adapters[domain][LIST_END].previous; _adapters[domain][previous].next = adapter; _adapters[domain][adapter].previous = previous; _adapters[domain][LIST_END].previous = adapter; _adapters[domain][adapter].next = LIST_END; _domains[domain].count++; } if (threshold < (_domains[domain].count / 2) + 1) revert InvalidThreshold(threshold); _domains[domain].threshold = threshold; emit AdaptersEnabled(domain, adapters); } /** * @dev Returns the hash unanimously agreed upon by all of the given adapters. * @param domain - Uint256 identifier for the domain to query. * @param id - Uint256 identifier to query. * @param adapters - Array of adapter addresses to query. * @return hash - Bytes32 hash agreed upon by the adapters for the given domain. * @notice adapters must be in numerical order from smallest to largest and contain no duplicates. * @notice Reverts if adapters are out of order or contain duplicates. * @notice Reverts if adapters disagree. * @notice Revert if the adapters do not yet have the hash for the given ID. * @notice Reverts if no adapters are set for the given domain. */ function _getHash(uint256 domain, uint256 id, IAdapter[] memory adapters) internal view returns (bytes32) { (uint256 threshold, uint256 count) = getThresholdAndCount(domain); if (adapters.length == 0) revert NoAdaptersGiven(); if (count == 0) revert NoAdaptersEnabled(domain); if (adapters.length < threshold) revert ThresholdNotMet(); checkAdapterOrderAndValidity(domain, adapters); return hashi.getHash(domain, id, adapters); } /** * @dev Returns the hash agreed upon by a threshold of the enabled adapters. * @param domain - Uint256 identifier for the domain to query. * @param id - Uint256 identifier to query. * @return hash - Bytes32 hash agreed upon by a threshold of the adapters for the given domain. * @notice If the threshold is set to 1, the function will return the hash of the first adapter in the list. * @notice Reverts if no threshold is not reached. * @notice Reverts if no adapters are set for the given domain. */ function _getThresholdHash(uint256 domain, uint256 id) internal view returns (bytes32 hash) { IAdapter[] memory adapters = getAdapters(domain); (uint256 threshold, uint256 count) = getThresholdAndCount(domain); if (count == 0) revert NoAdaptersEnabled(domain); if (adapters.length < threshold) revert ThresholdNotMet(); bytes32[] memory hashes = new bytes32[](adapters.length); for (uint256 i = 0; i < adapters.length; i++) { hashes[i] = adapters[i].getHash(domain, id); } for (uint256 i = 0; i < hashes.length; i++) { if (i > hashes.length - threshold) break; bytes32 baseHash = hashes[i]; if (baseHash == bytes32(0)) continue; uint256 num = 0; for (uint256 j = i; j < hashes.length; j++) { if (baseHash == hashes[j]) { num++; if (num == threshold) return hashes[i]; } } } revert ThresholdNotMet(); } /** * @dev Returns the hash unanimously agreed upon by ALL of the enabled adapters. * @param domain - Uint256 identifier for the domain to query. * @param id - Uint256 identifier to query. * @return hash - Bytes32 hash agreed upon by the adapters for the given domain. * @notice Reverts if adapters disagree. * @notice Revert if the adapters do not yet have the hash for the given ID. * @notice Reverts if no adapters are set for the given domain. */ function _getUnanimousHash(uint256 domain, uint256 id) internal view returns (bytes32 hash) { IAdapter[] memory adapters = getAdapters(domain); (uint256 threshold, uint256 count) = getThresholdAndCount(domain); if (count == 0) revert NoAdaptersEnabled(domain); if (adapters.length < threshold) revert ThresholdNotMet(); return hashi.getHash(domain, id, adapters); } /** * @dev Sets the address of the IHashi contract. * @param _hashi - Address of the hashi contract. * @notice Only callable by the owner of this contract. */ function _setHashi(IHashi _hashi) internal onlyOwner { if (hashi == _hashi) revert DuplicateHashiAddress(_hashi); hashi = _hashi; emit HashiSet(hashi); } /** * @dev Sets the threshold of adapters required for a given domain. * @param domain - Uint256 identifier for the domain for which to set the threshold. * @param threshold - Uint256 threshold to set for the given domain. * @notice Only callable by the owner of this contract. * @notice Reverts if threshold is already set to the given value. */ function _setThreshold(uint256 domain, uint256 threshold) internal onlyOwner { uint256 count = _domains[domain].count; if (count == 0) revert CountCannotBeZero(); if (threshold < (count / 2) + 1) revert InvalidThreshold(threshold); if (_domains[domain].threshold == threshold) revert DuplicateThreshold(threshold); _domains[domain].threshold = threshold; emit ThresholdSet(domain, threshold); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { IJushin } from "../interfaces/IJushin.sol"; import { IAdapter } from "../interfaces/IAdapter.sol"; contract PingPong is IJushin { uint256 public count; event Pong(uint256 count); function ping() external { count++; emit Pong(count); } function onMessage( uint256, uint256, address, uint256, IAdapter[] calldata, bytes calldata ) external returns (bytes memory) { count++; emit Pong(count); return abi.encode(0); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { IMessageHashCalculator } from "../interfaces/IMessageHashCalculator.sol"; import { Message } from "../interfaces/IMessage.sol"; contract MessageHashCalculator is IMessageHashCalculator { /// @inheritdoc IMessageHashCalculator function calculateMessageHash(Message memory message) public pure returns (bytes32) { return keccak256(abi.encode(message)); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { IMessageIdCalculator } from "../interfaces/IMessageIdCalculator.sol"; contract MessageIdCalculator is IMessageIdCalculator { /// @inheritdoc IMessageIdCalculator function calculateMessageId( uint256 sourceChainId, address dispatcherAddress, bytes32 messageHash ) public pure returns (uint256) { return uint256(keccak256(abi.encode(sourceChainId, dispatcherAddress, messageHash))); } }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.20; import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import { IYaru } from "./interfaces/IYaru.sol"; import { IHashi, IAdapter } from "./interfaces/IHashi.sol"; import { Message } from "./interfaces/IMessage.sol"; import { MessageIdCalculator } from "./utils/MessageIdCalculator.sol"; import { MessageHashCalculator } from "./utils/MessageHashCalculator.sol"; import { IJushin } from "./interfaces/IJushin.sol"; contract Yaru is IYaru, MessageIdCalculator, MessageHashCalculator, ReentrancyGuard { address public immutable HASHI; address public immutable YAHO; uint256 public immutable SOURCE_CHAIN_ID; mapping(uint256 => bool) public executed; constructor(address hashi, address yaho_, uint256 sourceChainId) { HASHI = hashi; YAHO = yaho_; SOURCE_CHAIN_ID = sourceChainId; } /// @inheritdoc IYaru function executeMessages(Message[] calldata messages) external nonReentrant returns (bytes[] memory) { bytes[] memory returnDatas = new bytes[](messages.length); for (uint256 i = 0; i < messages.length; ) { Message memory message = messages[i]; bytes32 messageHash = calculateMessageHash(message); uint256 messageId = calculateMessageId(SOURCE_CHAIN_ID, YAHO, messageHash); if (message.targetChainId != block.chainid) revert InvalidToChainId(message.targetChainId, block.chainid); if (executed[messageId]) revert MessageIdAlreadyExecuted(messageId); executed[messageId] = true; if ( !IHashi(HASHI).checkHashWithThresholdFromAdapters( SOURCE_CHAIN_ID, messageId, message.threshold, message.adapters ) ) revert ThresholdNotMet(); try IJushin(message.receiver).onMessage( messageId, SOURCE_CHAIN_ID, message.sender, message.threshold, message.adapters, message.data ) returns (bytes memory returnData) { returnDatas[i] = returnData; } catch { revert CallFailed(); } emit MessageExecuted(messageId, message); unchecked { ++i; } } return returnDatas; } }
// SPDX-License-Identifier: Apache-2.0 /* * @author Hamdi Allam [email protected] * Please reach out with any questions or concerns */ pragma solidity >=0.5.10 <0.9.0; library RLPReader { uint8 constant STRING_SHORT_START = 0x80; uint8 constant STRING_LONG_START = 0xb8; uint8 constant LIST_SHORT_START = 0xc0; uint8 constant LIST_LONG_START = 0xf8; uint8 constant WORD_SIZE = 32; struct RLPItem { uint256 len; uint256 memPtr; } struct Iterator { RLPItem item; // Item that's being iterated over. uint256 nextPtr; // Position of the next item in the list. } /* * @dev Returns the next element in the iteration. Reverts if it has not next element. * @param self The iterator. * @return The next element in the iteration. */ function next(Iterator memory self) internal pure returns (RLPItem memory) { require(hasNext(self)); uint256 ptr = self.nextPtr; uint256 itemLength = _itemLength(ptr); self.nextPtr = ptr + itemLength; return RLPItem(itemLength, ptr); } /* * @dev Returns true if the iteration has more elements. * @param self The iterator. * @return true if the iteration has more elements. */ function hasNext(Iterator memory self) internal pure returns (bool) { RLPItem memory item = self.item; return self.nextPtr < item.memPtr + item.len; } /* * @param item RLP encoded bytes */ function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) { uint256 memPtr; assembly { memPtr := add(item, 0x20) } return RLPItem(item.length, memPtr); } /* * @dev Create an iterator. Reverts if item is not a list. * @param self The RLP item. * @return An 'Iterator' over the item. */ function iterator(RLPItem memory self) internal pure returns (Iterator memory) { require(isList(self)); uint256 ptr = self.memPtr + _payloadOffset(self.memPtr); return Iterator(self, ptr); } /* * @param the RLP item. */ function rlpLen(RLPItem memory item) internal pure returns (uint256) { return item.len; } /* * @param the RLP item. * @return (memPtr, len) pair: location of the item's payload in memory. */ function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) { uint256 offset = _payloadOffset(item.memPtr); uint256 memPtr = item.memPtr + offset; uint256 len = item.len - offset; // data length return (memPtr, len); } /* * @param the RLP item. */ function payloadLen(RLPItem memory item) internal pure returns (uint256) { (, uint256 len) = payloadLocation(item); return len; } /* * @param the RLP item containing the encoded list. */ function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) { require(isList(item)); uint256 items = numItems(item); RLPItem[] memory result = new RLPItem[](items); uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 dataLen; for (uint256 i = 0; i < items; i++) { dataLen = _itemLength(memPtr); result[i] = RLPItem(dataLen, memPtr); memPtr = memPtr + dataLen; } return result; } // @return indicator whether encoded payload is a list. negate this function call for isData. function isList(RLPItem memory item) internal pure returns (bool) { if (item.len == 0) return false; uint8 byte0; uint256 memPtr = item.memPtr; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < LIST_SHORT_START) return false; return true; } /* * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory. * @return keccak256 hash of RLP encoded bytes. */ function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) { uint256 ptr = item.memPtr; uint256 len = item.len; bytes32 result; assembly { result := keccak256(ptr, len) } return result; } /* * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory. * @return keccak256 hash of the item payload. */ function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) { (uint256 memPtr, uint256 len) = payloadLocation(item); bytes32 result; assembly { result := keccak256(memPtr, len) } return result; } /** RLPItem conversions into data types **/ // @returns raw rlp encoding in bytes function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) { bytes memory result = new bytes(item.len); if (result.length == 0) return result; uint256 ptr; assembly { ptr := add(0x20, result) } copy(item.memPtr, ptr, item.len); return result; } // any non-zero byte except "0x80" is considered true function toBoolean(RLPItem memory item) internal pure returns (bool) { require(item.len == 1); uint256 result; uint256 memPtr = item.memPtr; assembly { result := byte(0, mload(memPtr)) } // SEE Github Issue #5. // Summary: Most commonly used RLP libraries (i.e Geth) will encode // "0" as "0x80" instead of as "0". We handle this edge case explicitly // here. if (result == 0 || result == STRING_SHORT_START) { return false; } else { return true; } } function toAddress(RLPItem memory item) internal pure returns (address) { // 1 byte for the length prefix require(item.len == 21); return address(uint160(toUint(item))); } function toUint(RLPItem memory item) internal pure returns (uint256) { require(item.len > 0 && item.len <= 33); (uint256 memPtr, uint256 len) = payloadLocation(item); uint256 result; assembly { result := mload(memPtr) // shift to the correct location if neccesary if lt(len, 32) { result := div(result, exp(256, sub(32, len))) } } return result; } // enforces 32 byte length function toUintStrict(RLPItem memory item) internal pure returns (uint256) { // one byte prefix require(item.len == 33); uint256 result; uint256 memPtr = item.memPtr + 1; assembly { result := mload(memPtr) } return result; } function toBytes(RLPItem memory item) internal pure returns (bytes memory) { require(item.len > 0); (uint256 memPtr, uint256 len) = payloadLocation(item); bytes memory result = new bytes(len); uint256 destPtr; assembly { destPtr := add(0x20, result) } copy(memPtr, destPtr, len); return result; } /* * Private Helpers */ // @return number of payload items inside an encoded list. function numItems(RLPItem memory item) private pure returns (uint256) { if (item.len == 0) return 0; uint256 count = 0; uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 endPtr = item.memPtr + item.len; while (currPtr < endPtr) { currPtr = currPtr + _itemLength(currPtr); // skip over an item count++; } return count; } // @return entire rlp item byte length function _itemLength(uint256 memPtr) private pure returns (uint256) { uint256 itemLen; uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) { itemLen = 1; } else if (byte0 < STRING_LONG_START) { itemLen = byte0 - STRING_SHORT_START + 1; } else if (byte0 < LIST_SHORT_START) { assembly { let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is memPtr := add(memPtr, 1) // skip over the first byte /* 32 byte word size */ let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len itemLen := add(dataLen, add(byteLen, 1)) } } else if (byte0 < LIST_LONG_START) { itemLen = byte0 - LIST_SHORT_START + 1; } else { assembly { let byteLen := sub(byte0, 0xf7) memPtr := add(memPtr, 1) let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length itemLen := add(dataLen, add(byteLen, 1)) } } return itemLen; } // @return number of bytes until the data function _payloadOffset(uint256 memPtr) private pure returns (uint256) { uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) { return 0; } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) { return 1; } else if (byte0 < LIST_SHORT_START) { // being explicit return byte0 - (STRING_LONG_START - 1) + 1; } else { return byte0 - (LIST_LONG_START - 1) + 1; } } /* * @param src Pointer to source * @param dest Pointer to destination * @param len Amount of memory to copy from the source */ function copy(uint256 src, uint256 dest, uint256 len) private pure { if (len == 0) return; // copy as many word sizes as possible for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } src += WORD_SIZE; dest += WORD_SIZE; } if (len > 0) { // left over bytes. Mask is used to remove unwanted bytes from the word uint256 mask = 256**(WORD_SIZE - len) - 1; assembly { let srcpart := and(mload(src), not(mask)) // zero out src let destpart := and(mload(dest), mask) // retrieve the bytes mstore(dest, or(destpart, srcpart)) } } } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 10000 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"targetChainId","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"contract IReporter[]","name":"reporters","type":"address[]"},{"internalType":"contract IAdapter[]","name":"adapters","type":"address[]"}],"internalType":"struct Message","name":"message","type":"tuple"}],"name":"InvalidMessage","type":"error"},{"inputs":[{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"uint256","name":"maxThreshold","type":"uint256"}],"name":"InvalidThreshold","type":"error"},{"inputs":[{"internalType":"uint256","name":"messageId","type":"uint256"}],"name":"MessageHashNotFound","type":"error"},{"inputs":[],"name":"NoAdaptersGiven","type":"error"},{"inputs":[],"name":"NoMessageIdsGiven","type":"error"},{"inputs":[],"name":"NoMessagesGiven","type":"error"},{"inputs":[],"name":"NoReportersGiven","type":"error"},{"inputs":[{"internalType":"uint256","name":"arrayOne","type":"uint256"},{"internalType":"uint256","name":"arrayTwo","type":"uint256"}],"name":"UnequalArrayLengths","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"messageId","type":"uint256"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"targetChainId","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"contract IReporter[]","name":"reporters","type":"address[]"},{"internalType":"contract IAdapter[]","name":"adapters","type":"address[]"}],"indexed":false,"internalType":"struct Message","name":"message","type":"tuple"}],"name":"MessageDispatched","type":"event"},{"inputs":[{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"targetChainId","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"contract IReporter[]","name":"reporters","type":"address[]"},{"internalType":"contract IAdapter[]","name":"adapters","type":"address[]"}],"internalType":"struct Message","name":"message","type":"tuple"}],"name":"calculateMessageHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"sourceChainId","type":"uint256"},{"internalType":"address","name":"dispatcherAddress","type":"address"},{"internalType":"bytes32","name":"messageHash","type":"bytes32"}],"name":"calculateMessageId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"currentNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"targetChainId","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"contract IReporter[]","name":"reporters","type":"address[]"},{"internalType":"contract IAdapter[]","name":"adapters","type":"address[]"}],"name":"dispatchMessage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"targetChainId","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"contract IReporter[]","name":"reporters","type":"address[]"},{"internalType":"contract IAdapter[]","name":"adapters","type":"address[]"}],"name":"dispatchMessageToAdapters","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"targetChainId","type":"uint256"},{"internalType":"uint256[]","name":"thresholds","type":"uint256[]"},{"internalType":"address[]","name":"receivers","type":"address[]"},{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"contract IReporter[]","name":"reporters","type":"address[]"},{"internalType":"contract IAdapter[]","name":"adapters","type":"address[]"}],"name":"dispatchMessagesToAdapters","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"messageId","type":"uint256"}],"name":"getPendingMessageHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"targetChainId","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"contract IReporter[]","name":"reporters","type":"address[]"},{"internalType":"contract IAdapter[]","name":"adapters","type":"address[]"}],"internalType":"struct Message[]","name":"messages","type":"tuple[]"}],"name":"relayMessagesToAdapters","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"payable","type":"function"}]
Contract Creation Code
6080806040523461001657611305908161001c8239f35b600080fdfe610140604052600436101561001357600080fd5b60003560e01c806331fa321b14610ab657806339d0bf63146109df5780633db59eeb146108a1578063543836b11461085e578063553c19dd1461049d578063adb610a31461047f578063b38fda7c146100a65763feed46df1461007557600080fd5b346100a15760206003193601126100a15760043560005260006020526020604060002054604051908152f35b600080fd5b60c06003193601126100a15760243567ffffffffffffffff81116100a1576100d2903690600401610b1a565b9060443567ffffffffffffffff81116100a1576100f3903690600401610b1a565b9260643567ffffffffffffffff81116100a157610114903690600401610b1a565b94909160843567ffffffffffffffff81116100a157610137903690600401610b1a565b60a05260805260a43567ffffffffffffffff81116100a15761015d903690600401610b1a565b60c05260e052818103610449578581036104125761017a82610e52565b6101005261018782610e52565b6101205260005b828110610202576101a060a051610e52565b506101fe6101d66101b63660a051608051610d11565b6101c53660c05160e051610d11565b90610120516101005160043561112c565b604051918291604083526101f06040840161010051610bf3565b908382036020850152610bf3565b0390f35b61020d818388610e83565b3560a051156103e85760c051156103be5760c05160a051036103845760a0518111801561037c575b6103435750610245818388610e83565b3590610252818588610e83565b359173ffffffffffffffffffffffffffffffffffffffff831683036100a15788821015610314578160051b8601357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1873603018112156100a15786019267ffffffffffffffff8435116100a1578335360360208501136100a1576001936102f29260c0519260e0519260a05192608051926020833593019160043561105f565b6102ff8361012051610ea0565b5261030d8261010051610ea0565b520161018e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b604490604051907f7b7a98f1000000000000000000000000000000000000000000000000000000008252600482015260a0516024820152fd5b508015610235565b60446040517fdf9ccef500000000000000000000000000000000000000000000000000000000815260a051600482015260c0516024820152fd5b60046040517fc77f9c81000000000000000000000000000000000000000000000000000000008152fd5b60046040517f66ab7afe000000000000000000000000000000000000000000000000000000008152fd5b60449086604051917fdf9ccef500000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b604491604051917fdf9ccef500000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b346100a15760006003193601126100a1576020600154604051908152f35b60206003193601126100a15760043567ffffffffffffffff81116100a1576104c9903690600401610b1a565b80156108345760206104db8284610eb4565b01356104f46104ea8385610eb4565b60c0810190610eed565b61050b6105018587610eb4565b60e0810190610eed565b919060405193828593602085019760808601908952606060408701525260a08401919060005b8181106107f75750505080601f19846020930301606085015284815201909260005b8181106107bc57505061056f925003601f198101835282610c8f565b51902061057b82610e52565b9061058583610e52565b9060005b8481106105f6576101fe6105e2868887876105dc60206105a98686610eb4565b0135946105d46105ca6105016105c26104ea858a610eb4565b949098610eb4565b9690923691610d11565b943691610d11565b9361112c565b604051918291602083526020830190610bf3565b8060051b8601357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01873603018112156100a1576106369036908801610d67565b8115158061075a575b6107205761064f61065691611264565b304661127f565b80600052600060205260406000205480156106ef576106758387610ea0565b52806106818386610ea0565b526000526000602052600060408120557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146106c057600101610589565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b602482604051907f92e4a25e0000000000000000000000000000000000000000000000000000000082526004820152fd5b610756906040519182917f69b2c1a400000000000000000000000000000000000000000000000000000000835260048301610f8b565b0390fd5b5060208101516107916107b160c08401516107a360e086015160405194859360208501978852606060408601526080850190610f41565b90601f19848303016060850152610f41565b03601f198101835282610c8f565b51902083141561063f565b9160019193506020809173ffffffffffffffffffffffffffffffffffffffff6107e488610af9565b1681520194019101918492939193610553565b91939594509160208060019273ffffffffffffffffffffffffffffffffffffffff61082188610af9565b1681520194019101918694959392610531565b60046040517f6832f637000000000000000000000000000000000000000000000000000000008152fd5b346100a15760206003193601126100a15760043567ffffffffffffffff81116100a1576108996108946020923690600401610d67565b611264565b604051908152f35b6108aa36610b4b565b949092939196979587156103e85785156103be578588036109a85787891180156109a0575b610969578584898761090197966108f9966108ef9661094c9e9f8e61105f565b9490983691610d11565b933691610d11565b926040519061090f82610c73565b60018252602036818401376040519261092784610c73565b60018452602036818601378761093c84610e93565b5261094684610e93565b5261112c565b906101fe6040519283928352604060208401526040830190610bf3565b60448989604051917f7b7a98f100000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5088156108cf565b60448887604051917fdf9ccef500000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b346100a1576109ed36610b4b565b97829692979197959395156103e85788156103be57888703610a7f578682118015610a77575b610a405791610a2a9795939160209997959361105f565b8160005260008352604060002055604051908152f35b60448288604051917f7b7a98f100000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b508115610a13565b6044878a604051917fdf9ccef500000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b346100a15760606003193601126100a15760243573ffffffffffffffffffffffffffffffffffffffff811681036100a1576108996020916044359060043561127f565b359073ffffffffffffffffffffffffffffffffffffffff821682036100a157565b9181601f840112156100a15782359167ffffffffffffffff83116100a1576020808501948460051b0101116100a157565b60c06003198201126100a157600435916024359160443573ffffffffffffffffffffffffffffffffffffffff811681036100a157916064359167ffffffffffffffff908184116100a157806023850112156100a1578360040135938285116100a15781602486830101116100a15760240193926084358381116100a15782610bd591600401610b1a565b9390939260a4359182116100a157610bef91600401610b1a565b9091565b90815180825260208080930193019160005b828110610c13575050505090565b835185529381019392810192600101610c05565b610100810190811067ffffffffffffffff821117610c4457604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040810190811067ffffffffffffffff821117610c4457604052565b90601f601f19910116810190811067ffffffffffffffff821117610c4457604052565b92919267ffffffffffffffff8211610c445760405191610cdc6020601f19601f8401160184610c8f565b8294818452818301116100a1578281602093846000960137010152565b67ffffffffffffffff8111610c445760051b60200190565b9291610d1c82610cf9565b91610d2a6040519384610c8f565b829481845260208094019160051b81019283116100a157905b828210610d505750505050565b838091610d5c84610af9565b815201910190610d43565b9190610100838203126100a15760405190610d8182610c27565b8193803583526020810135602084015260408101356040840152610da760608201610af9565b6060840152610db860808201610af9565b608084015267ffffffffffffffff9060a08101358281116100a157810183601f820112156100a15783816020610df093359101610cb2565b60a085015260c08101358281116100a157810183601f820112156100a15783816020610e1e93359101610d11565b60c085015260e08101359182116100a1570181601f820112156100a15760e091816020610e4d93359101610d11565b910152565b90610e5c82610cf9565b610e696040519182610c8f565b828152601f19610e798294610cf9565b0190602036910137565b91908110156103145760051b0190565b8051156103145760200190565b80518210156103145760209160051b010190565b9015610314578035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01813603018212156100a1570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156100a1570180359067ffffffffffffffff82116100a157602001918160051b360383136100a157565b90815180825260208080930193019160005b828110610f61575050505090565b835173ffffffffffffffffffffffffffffffffffffffff1685529381019392810192600101610f53565b60208082528251818301528083015160408301526040830151606083015273ffffffffffffffffffffffffffffffffffffffff80606085015116608084015260808401511660a083015260a0830151610100918260c085015281519061012092828487015260005b83811061104a575050509160e0611037611047969593601f95610140906000828289010152601f199788910116860160c08901519287820301858801520190610f41565b9401519282850301910152610f41565b90565b81810183015187820161014001528201610ff3565b96959291989794939098600154996040519861107a8a610c27565b8b8a5260208a0152604089015233606089015273ffffffffffffffffffffffffffffffffffffffff16608088015236906110b392610cb2565b60a086015236906110c392610d11565b60c084015236906110d392610d11565b60e08201526110e181611264565b926110ed84304661127f565b916001839201600155604051611104819282610f8b565b037f218247aabc759e65b5bb92ccc074f9d62cd187259f2a0984c3c9cf91f67ff7cf91a29190565b919493909461113b8451610e52565b9360005b815181101561125a5773ffffffffffffffffffffffffffffffffffffffff90816111698285610ea0565b51168061117c575b50600191500161113f565b6111f29261118a8388610ea0565b51166040918251917fb4a90ff7000000000000000000000000000000000000000000000000000000008352896004840152602483015260806044830152816111d68d6084830190610bf3565b91600319828403016064830152816000816020998a968d610bf3565b03925af1918215611250575060009161121c575b50600192506112158289610ea0565b5238611171565b919282813d8311611249575b6112328183610c8f565b810103126112465750906001915138611206565b80fd5b503d611228565b513d6000823e3d90fd5b5093955050505050565b604051611279816107a3602082019485610f8b565b51902090565b9173ffffffffffffffffffffffffffffffffffffffff60405192602084019485521660408301526060820152606081526080810181811067ffffffffffffffff821117610c44576040525190209056fea2646970667358221220d24abdbcfba11e40dd78858a66703945ad610bdbe3f6e2a12202af355b15845864736f6c63430008140033
Deployed Bytecode
0x610140604052600436101561001357600080fd5b60003560e01c806331fa321b14610ab657806339d0bf63146109df5780633db59eeb146108a1578063543836b11461085e578063553c19dd1461049d578063adb610a31461047f578063b38fda7c146100a65763feed46df1461007557600080fd5b346100a15760206003193601126100a15760043560005260006020526020604060002054604051908152f35b600080fd5b60c06003193601126100a15760243567ffffffffffffffff81116100a1576100d2903690600401610b1a565b9060443567ffffffffffffffff81116100a1576100f3903690600401610b1a565b9260643567ffffffffffffffff81116100a157610114903690600401610b1a565b94909160843567ffffffffffffffff81116100a157610137903690600401610b1a565b60a05260805260a43567ffffffffffffffff81116100a15761015d903690600401610b1a565b60c05260e052818103610449578581036104125761017a82610e52565b6101005261018782610e52565b6101205260005b828110610202576101a060a051610e52565b506101fe6101d66101b63660a051608051610d11565b6101c53660c05160e051610d11565b90610120516101005160043561112c565b604051918291604083526101f06040840161010051610bf3565b908382036020850152610bf3565b0390f35b61020d818388610e83565b3560a051156103e85760c051156103be5760c05160a051036103845760a0518111801561037c575b6103435750610245818388610e83565b3590610252818588610e83565b359173ffffffffffffffffffffffffffffffffffffffff831683036100a15788821015610314578160051b8601357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1873603018112156100a15786019267ffffffffffffffff8435116100a1578335360360208501136100a1576001936102f29260c0519260e0519260a05192608051926020833593019160043561105f565b6102ff8361012051610ea0565b5261030d8261010051610ea0565b520161018e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b604490604051907f7b7a98f1000000000000000000000000000000000000000000000000000000008252600482015260a0516024820152fd5b508015610235565b60446040517fdf9ccef500000000000000000000000000000000000000000000000000000000815260a051600482015260c0516024820152fd5b60046040517fc77f9c81000000000000000000000000000000000000000000000000000000008152fd5b60046040517f66ab7afe000000000000000000000000000000000000000000000000000000008152fd5b60449086604051917fdf9ccef500000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b604491604051917fdf9ccef500000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b346100a15760006003193601126100a1576020600154604051908152f35b60206003193601126100a15760043567ffffffffffffffff81116100a1576104c9903690600401610b1a565b80156108345760206104db8284610eb4565b01356104f46104ea8385610eb4565b60c0810190610eed565b61050b6105018587610eb4565b60e0810190610eed565b919060405193828593602085019760808601908952606060408701525260a08401919060005b8181106107f75750505080601f19846020930301606085015284815201909260005b8181106107bc57505061056f925003601f198101835282610c8f565b51902061057b82610e52565b9061058583610e52565b9060005b8481106105f6576101fe6105e2868887876105dc60206105a98686610eb4565b0135946105d46105ca6105016105c26104ea858a610eb4565b949098610eb4565b9690923691610d11565b943691610d11565b9361112c565b604051918291602083526020830190610bf3565b8060051b8601357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01873603018112156100a1576106369036908801610d67565b8115158061075a575b6107205761064f61065691611264565b304661127f565b80600052600060205260406000205480156106ef576106758387610ea0565b52806106818386610ea0565b526000526000602052600060408120557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146106c057600101610589565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b602482604051907f92e4a25e0000000000000000000000000000000000000000000000000000000082526004820152fd5b610756906040519182917f69b2c1a400000000000000000000000000000000000000000000000000000000835260048301610f8b565b0390fd5b5060208101516107916107b160c08401516107a360e086015160405194859360208501978852606060408601526080850190610f41565b90601f19848303016060850152610f41565b03601f198101835282610c8f565b51902083141561063f565b9160019193506020809173ffffffffffffffffffffffffffffffffffffffff6107e488610af9565b1681520194019101918492939193610553565b91939594509160208060019273ffffffffffffffffffffffffffffffffffffffff61082188610af9565b1681520194019101918694959392610531565b60046040517f6832f637000000000000000000000000000000000000000000000000000000008152fd5b346100a15760206003193601126100a15760043567ffffffffffffffff81116100a1576108996108946020923690600401610d67565b611264565b604051908152f35b6108aa36610b4b565b949092939196979587156103e85785156103be578588036109a85787891180156109a0575b610969578584898761090197966108f9966108ef9661094c9e9f8e61105f565b9490983691610d11565b933691610d11565b926040519061090f82610c73565b60018252602036818401376040519261092784610c73565b60018452602036818601378761093c84610e93565b5261094684610e93565b5261112c565b906101fe6040519283928352604060208401526040830190610bf3565b60448989604051917f7b7a98f100000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5088156108cf565b60448887604051917fdf9ccef500000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b346100a1576109ed36610b4b565b97829692979197959395156103e85788156103be57888703610a7f578682118015610a77575b610a405791610a2a9795939160209997959361105f565b8160005260008352604060002055604051908152f35b60448288604051917f7b7a98f100000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b508115610a13565b6044878a604051917fdf9ccef500000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b346100a15760606003193601126100a15760243573ffffffffffffffffffffffffffffffffffffffff811681036100a1576108996020916044359060043561127f565b359073ffffffffffffffffffffffffffffffffffffffff821682036100a157565b9181601f840112156100a15782359167ffffffffffffffff83116100a1576020808501948460051b0101116100a157565b60c06003198201126100a157600435916024359160443573ffffffffffffffffffffffffffffffffffffffff811681036100a157916064359167ffffffffffffffff908184116100a157806023850112156100a1578360040135938285116100a15781602486830101116100a15760240193926084358381116100a15782610bd591600401610b1a565b9390939260a4359182116100a157610bef91600401610b1a565b9091565b90815180825260208080930193019160005b828110610c13575050505090565b835185529381019392810192600101610c05565b610100810190811067ffffffffffffffff821117610c4457604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040810190811067ffffffffffffffff821117610c4457604052565b90601f601f19910116810190811067ffffffffffffffff821117610c4457604052565b92919267ffffffffffffffff8211610c445760405191610cdc6020601f19601f8401160184610c8f565b8294818452818301116100a1578281602093846000960137010152565b67ffffffffffffffff8111610c445760051b60200190565b9291610d1c82610cf9565b91610d2a6040519384610c8f565b829481845260208094019160051b81019283116100a157905b828210610d505750505050565b838091610d5c84610af9565b815201910190610d43565b9190610100838203126100a15760405190610d8182610c27565b8193803583526020810135602084015260408101356040840152610da760608201610af9565b6060840152610db860808201610af9565b608084015267ffffffffffffffff9060a08101358281116100a157810183601f820112156100a15783816020610df093359101610cb2565b60a085015260c08101358281116100a157810183601f820112156100a15783816020610e1e93359101610d11565b60c085015260e08101359182116100a1570181601f820112156100a15760e091816020610e4d93359101610d11565b910152565b90610e5c82610cf9565b610e696040519182610c8f565b828152601f19610e798294610cf9565b0190602036910137565b91908110156103145760051b0190565b8051156103145760200190565b80518210156103145760209160051b010190565b9015610314578035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01813603018212156100a1570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156100a1570180359067ffffffffffffffff82116100a157602001918160051b360383136100a157565b90815180825260208080930193019160005b828110610f61575050505090565b835173ffffffffffffffffffffffffffffffffffffffff1685529381019392810192600101610f53565b60208082528251818301528083015160408301526040830151606083015273ffffffffffffffffffffffffffffffffffffffff80606085015116608084015260808401511660a083015260a0830151610100918260c085015281519061012092828487015260005b83811061104a575050509160e0611037611047969593601f95610140906000828289010152601f199788910116860160c08901519287820301858801520190610f41565b9401519282850301910152610f41565b90565b81810183015187820161014001528201610ff3565b96959291989794939098600154996040519861107a8a610c27565b8b8a5260208a0152604089015233606089015273ffffffffffffffffffffffffffffffffffffffff16608088015236906110b392610cb2565b60a086015236906110c392610d11565b60c084015236906110d392610d11565b60e08201526110e181611264565b926110ed84304661127f565b916001839201600155604051611104819282610f8b565b037f218247aabc759e65b5bb92ccc074f9d62cd187259f2a0984c3c9cf91f67ff7cf91a29190565b919493909461113b8451610e52565b9360005b815181101561125a5773ffffffffffffffffffffffffffffffffffffffff90816111698285610ea0565b51168061117c575b50600191500161113f565b6111f29261118a8388610ea0565b51166040918251917fb4a90ff7000000000000000000000000000000000000000000000000000000008352896004840152602483015260806044830152816111d68d6084830190610bf3565b91600319828403016064830152816000816020998a968d610bf3565b03925af1918215611250575060009161121c575b50600192506112158289610ea0565b5238611171565b919282813d8311611249575b6112328183610c8f565b810103126112465750906001915138611206565b80fd5b503d611228565b513d6000823e3d90fd5b5093955050505050565b604051611279816107a3602082019485610f8b565b51902090565b9173ffffffffffffffffffffffffffffffffffffffff60405192602084019485521660408301526060820152606081526080810181811067ffffffffffffffff821117610c44576040525190209056fea2646970667358221220d24abdbcfba11e40dd78858a66703945ad610bdbe3f6e2a12202af355b15845864736f6c63430008140033
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.