Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 899 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Send Ohm | 21246504 | 15 mins ago | IN | 0.00030588 ETH | 0.00341404 | ||||
Send Ohm | 21244671 | 6 hrs ago | IN | 0.0002791 ETH | 0.00332435 | ||||
Send Ohm | 21240593 | 20 hrs ago | IN | 0.00031305 ETH | 0.00304192 | ||||
Send Ohm | 21240592 | 20 hrs ago | IN | 0.01 ETH | 0.00060916 | ||||
Send Ohm | 21240592 | 20 hrs ago | IN | 0.00030121 ETH | 0.00334939 | ||||
Send Ohm | 21240591 | 20 hrs ago | IN | 0.01 ETH | 0.00061679 | ||||
Send Ohm | 21240591 | 20 hrs ago | IN | 0.00030121 ETH | 0.00314498 | ||||
Send Ohm | 21240247 | 21 hrs ago | IN | 0.00027704 ETH | 0.0026164 | ||||
Send Ohm | 21240042 | 21 hrs ago | IN | 0.00027788 ETH | 0.00247581 | ||||
Send Ohm | 21239585 | 23 hrs ago | IN | 0.00027782 ETH | 0.00371255 | ||||
Send Ohm | 21239059 | 25 hrs ago | IN | 0.00027888 ETH | 0.00336759 | ||||
Send Ohm | 21238932 | 25 hrs ago | IN | 0.00027888 ETH | 0.00348106 | ||||
Send Ohm | 21237396 | 30 hrs ago | IN | 0.00031627 ETH | 0.00466911 | ||||
Send Ohm | 21237144 | 31 hrs ago | IN | 0.00034185 ETH | 0.00578964 | ||||
Send Ohm | 21236078 | 35 hrs ago | IN | 0.00032643 ETH | 0.00689299 | ||||
Send Ohm | 21236063 | 35 hrs ago | IN | 0.00032643 ETH | 0.00734097 | ||||
Send Ohm | 21224619 | 3 days ago | IN | 0.00032643 ETH | 0.00393944 | ||||
Send Ohm | 21220869 | 3 days ago | IN | 0.00029651 ETH | 0.00177698 | ||||
Send Ohm | 21220652 | 3 days ago | IN | 0.00032643 ETH | 0.00270329 | ||||
Send Ohm | 21220496 | 3 days ago | IN | 0.00032643 ETH | 0.00248286 | ||||
Send Ohm | 21218956 | 3 days ago | IN | 0.00030464 ETH | 0.00271096 | ||||
Send Ohm | 21218494 | 3 days ago | IN | 0.00029607 ETH | 0.00291378 | ||||
Send Ohm | 21218467 | 3 days ago | IN | 0.0003709 ETH | 0.00248496 | ||||
Send Ohm | 21218464 | 3 days ago | IN | 0.00029559 ETH | 0.00298933 | ||||
Send Ohm | 21218462 | 3 days ago | IN | 0.00033718 ETH | 0.00035569 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
21246504 | 15 mins ago | 0.00030588 ETH | ||||
21244671 | 6 hrs ago | 0.0002791 ETH | ||||
21240593 | 20 hrs ago | 0.00031305 ETH | ||||
21240592 | 20 hrs ago | 0.00030121 ETH | ||||
21240591 | 20 hrs ago | 0.00030121 ETH | ||||
21240247 | 21 hrs ago | 0.00027704 ETH | ||||
21240042 | 21 hrs ago | 0.00027788 ETH | ||||
21239585 | 23 hrs ago | 0.00027782 ETH | ||||
21239059 | 25 hrs ago | 0.00027888 ETH | ||||
21238932 | 25 hrs ago | 0.00027888 ETH | ||||
21237396 | 30 hrs ago | 0.00031627 ETH | ||||
21237144 | 31 hrs ago | 0.00034185 ETH | ||||
21236078 | 35 hrs ago | 0.00032643 ETH | ||||
21236063 | 35 hrs ago | 0.00032643 ETH | ||||
21224619 | 3 days ago | 0.00032643 ETH | ||||
21220869 | 3 days ago | 0.00029651 ETH | ||||
21220652 | 3 days ago | 0.00032643 ETH | ||||
21220496 | 3 days ago | 0.00032643 ETH | ||||
21218956 | 3 days ago | 0.00030464 ETH | ||||
21218494 | 3 days ago | 0.00029607 ETH | ||||
21218467 | 3 days ago | 0.0003709 ETH | ||||
21218464 | 3 days ago | 0.00029559 ETH | ||||
21218098 | 3 days ago | 0.00033718 ETH | ||||
21215555 | 4 days ago | 0.00032625 ETH | ||||
21215543 | 4 days ago | 0.00029851 ETH |
Loading...
Loading
Contract Name:
CrossChainBridge
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 10 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.15; import {ERC20} from "solmate/tokens/ERC20.sol"; import {ILayerZeroUserApplicationConfig} from "layer-zero/interfaces/ILayerZeroUserApplicationConfig.sol"; import {ILayerZeroEndpoint} from "layer-zero/interfaces/ILayerZeroEndpoint.sol"; import {ILayerZeroReceiver} from "layer-zero/interfaces/ILayerZeroReceiver.sol"; import {BytesLib} from "layer-zero/util/BytesLib.sol"; import {RolesConsumer} from "modules/ROLES/OlympusRoles.sol"; import {ROLESv1} from "modules/ROLES/ROLES.v1.sol"; import {MINTRv1} from "modules/MINTR/MINTR.v1.sol"; import "src/Kernel.sol"; /// @notice Message bridge for cross-chain OHM transfers. /// @dev Uses LayerZero as communication protocol. /// @dev Each chain needs to `setTrustedRemoteAddress` for each remote address /// it intends to receive from. contract CrossChainBridge is Policy, RolesConsumer, ILayerZeroReceiver, ILayerZeroUserApplicationConfig { using BytesLib for bytes; // Bridge errors error Bridge_InsufficientAmount(); error Bridge_InvalidCaller(); error Bridge_InvalidMessageSource(); error Bridge_NoStoredMessage(); error Bridge_InvalidPayload(); error Bridge_DestinationNotTrusted(); error Bridge_NoTrustedPath(); error Bridge_Deactivated(); error Bridge_TrustedRemoteUninitialized(); // Bridge-specific events event BridgeTransferred(address indexed sender_, uint256 amount_, uint16 indexed dstChain_); event BridgeReceived(address indexed receiver_, uint256 amount_, uint16 indexed srcChain_); // LZ app events event MessageFailed( uint16 srcChainId_, bytes srcAddress_, uint64 nonce_, bytes payload_, bytes reason_ ); event RetryMessageSuccess( uint16 srcChainId_, bytes srcAddress_, uint64 nonce_, bytes32 payloadHash_ ); event SetPrecrime(address precrime_); event SetTrustedRemote(uint16 remoteChainId_, bytes path_); event SetTrustedRemoteAddress(uint16 remoteChainId_, bytes remoteAddress_); event SetMinDstGas(uint16 dstChainId_, uint16 type_, uint256 _minDstGas); event BridgeStatusSet(bool isActive_); // Modules MINTRv1 public MINTR; ILayerZeroEndpoint public immutable lzEndpoint; ERC20 public ohm; /// @notice Flag to determine if bridge is allowed to send messages or not bool public bridgeActive; // LZ app state /// @notice Storage for failed messages on receive. /// @notice chainID => source address => endpoint nonce mapping(uint16 => mapping(bytes => mapping(uint64 => bytes32))) public failedMessages; /// @notice Trusted remote paths. Must be set by admin. mapping(uint16 => bytes) public trustedRemoteLookup; /// @notice LZ precrime address. Currently unused. address public precrime; //============================================================================================// // POLICY SETUP // //============================================================================================// constructor(Kernel kernel_, address endpoint_) Policy(kernel_) { lzEndpoint = ILayerZeroEndpoint(endpoint_); bridgeActive = true; } /// @inheritdoc Policy function configureDependencies() external override returns (Keycode[] memory dependencies) { dependencies = new Keycode[](2); dependencies[0] = toKeycode("MINTR"); dependencies[1] = toKeycode("ROLES"); MINTR = MINTRv1(getModuleAddress(dependencies[0])); ROLES = ROLESv1(getModuleAddress(dependencies[1])); ohm = ERC20(address(MINTR.ohm())); } /// @inheritdoc Policy function requestPermissions() external view override returns (Permissions[] memory permissions) { Keycode MINTR_KEYCODE = MINTR.KEYCODE(); permissions = new Permissions[](3); permissions[0] = Permissions(MINTR_KEYCODE, MINTR.mintOhm.selector); permissions[1] = Permissions(MINTR_KEYCODE, MINTR.burnOhm.selector); permissions[2] = Permissions(MINTR_KEYCODE, MINTR.increaseMintApproval.selector); } //============================================================================================// // CORE FUNCTIONS // //============================================================================================// /// @notice Send OHM to an eligible chain function sendOhm(uint16 dstChainId_, address to_, uint256 amount_) external payable { if (!bridgeActive) revert Bridge_Deactivated(); if (ohm.balanceOf(msg.sender) < amount_) revert Bridge_InsufficientAmount(); bytes memory payload = abi.encode(to_, amount_); MINTR.burnOhm(msg.sender, amount_); _sendMessage(dstChainId_, payload, payable(msg.sender), address(0x0), bytes(""), msg.value); emit BridgeTransferred(msg.sender, amount_, dstChainId_); } /// @notice Implementation of receiving an LZ message /// @dev Function must be public to be called by low-level call in lzReceive function _receiveMessage( uint16 srcChainId_, bytes memory, uint64, bytes memory payload_ ) internal { (address to, uint256 amount) = abi.decode(payload_, (address, uint256)); MINTR.increaseMintApproval(address(this), amount); MINTR.mintOhm(to, amount); emit BridgeReceived(to, amount, srcChainId_); } // ========= LZ Receive Functions ========= // /// @inheritdoc ILayerZeroReceiver function lzReceive( uint16 srcChainId_, bytes calldata srcAddress_, uint64 nonce_, bytes calldata payload_ ) public virtual override { // lzReceive must be called by the endpoint for security if (msg.sender != address(lzEndpoint)) revert Bridge_InvalidCaller(); // Will still block the message pathway from (srcChainId, srcAddress). // Should not receive messages from untrusted remote. bytes memory trustedRemote = trustedRemoteLookup[srcChainId_]; if ( trustedRemote.length == 0 || srcAddress_.length != trustedRemote.length || keccak256(srcAddress_) != keccak256(trustedRemote) ) revert Bridge_InvalidMessageSource(); // NOTE: Use low-level call to handle any errors. We trust the underlying receive // implementation, so we are doing a regular call vs using ExcessivelySafeCall (bool success, bytes memory reason) = address(this).call( abi.encodeWithSelector( this.receiveMessage.selector, srcChainId_, srcAddress_, nonce_, payload_ ) ); // If message fails, store message for retry if (!success) { failedMessages[srcChainId_][srcAddress_][nonce_] = keccak256(payload_); emit MessageFailed(srcChainId_, srcAddress_, nonce_, payload_, reason); } } /// @notice Implementation of receiving an LZ message /// @dev Function must be public to be called by low-level call in lzReceive function receiveMessage( uint16 srcChainId_, bytes memory srcAddress_, uint64 nonce_, bytes memory payload_ ) public { // Needed to restrict access to low-level call from lzReceive if (msg.sender != address(this)) revert Bridge_InvalidCaller(); _receiveMessage(srcChainId_, srcAddress_, nonce_, payload_); } /// @notice Retry a failed receive message function retryMessage( uint16 srcChainId_, bytes calldata srcAddress_, uint64 nonce_, bytes calldata payload_ ) public payable virtual { // Assert there is message to retry bytes32 payloadHash = failedMessages[srcChainId_][srcAddress_][nonce_]; if (payloadHash == bytes32(0)) revert Bridge_NoStoredMessage(); if (keccak256(payload_) != payloadHash) revert Bridge_InvalidPayload(); // Clear the stored message failedMessages[srcChainId_][srcAddress_][nonce_] = bytes32(0); // Execute the message. revert if it fails again _receiveMessage(srcChainId_, srcAddress_, nonce_, payload_); emit RetryMessageSuccess(srcChainId_, srcAddress_, nonce_, payloadHash); } // ========= LZ Send Functions ========= // /// @notice Internal function for sending a message across chains. /// @dev Params defined in ILayerZeroEndpoint `send` function. function _sendMessage( uint16 dstChainId_, bytes memory payload_, address payable refundAddress_, address zroPaymentAddress_, bytes memory adapterParams_, uint256 nativeFee_ ) internal { bytes memory trustedRemote = trustedRemoteLookup[dstChainId_]; if (trustedRemote.length == 0) revert Bridge_DestinationNotTrusted(); // solhint-disable-next-line lzEndpoint.send{value: nativeFee_}( dstChainId_, trustedRemote, payload_, refundAddress_, zroPaymentAddress_, adapterParams_ ); } /// @notice Function to estimate how much gas is needed to send OHM /// @dev Should be called by frontend before making sendOhm call. /// @return nativeFee - Native token amount to send to sendOhm /// @return zroFee - Fee paid in ZRO token. Unused. function estimateSendFee( uint16 dstChainId_, address to_, uint256 amount_, bytes calldata adapterParams_ ) external view returns (uint256 nativeFee, uint256 zroFee) { // Mock the payload for sendOhm() bytes memory payload = abi.encode(to_, amount_); return lzEndpoint.estimateFees(dstChainId_, address(this), payload, false, adapterParams_); } // ========= LZ UserApplication & Admin config ========= // /// @notice Generic config for LayerZero User Application function setConfig( uint16 version_, uint16 chainId_, uint256 configType_, bytes calldata config_ ) external override onlyRole("bridge_admin") { lzEndpoint.setConfig(version_, chainId_, configType_, config_); } /// @notice Set send version of endpoint to be used by LayerZero User Application function setSendVersion(uint16 version_) external override onlyRole("bridge_admin") { lzEndpoint.setSendVersion(version_); } /// @notice Set receive version of endpoint to be used by LayerZero User Application function setReceiveVersion(uint16 version_) external override onlyRole("bridge_admin") { lzEndpoint.setReceiveVersion(version_); } /// @notice Retries a received message. Used as last resort if retryPayload fails. /// @dev Unblocks queue and DESTROYS transaction forever. USE WITH CAUTION. function forceResumeReceive( uint16 srcChainId_, bytes calldata srcAddress_ ) external override onlyRole("bridge_admin") { lzEndpoint.forceResumeReceive(srcChainId_, srcAddress_); } /// @notice Sets the trusted path for the cross-chain communication /// @dev path_ = abi.encodePacked(remoteAddress, localAddress) function setTrustedRemote( uint16 srcChainId_, bytes calldata path_ ) external onlyRole("bridge_admin") { trustedRemoteLookup[srcChainId_] = path_; emit SetTrustedRemote(srcChainId_, path_); } /// @notice Convenience function for setting trusted paths between EVM addresses function setTrustedRemoteAddress( uint16 remoteChainId_, bytes calldata remoteAddress_ ) external onlyRole("bridge_admin") { trustedRemoteLookup[remoteChainId_] = abi.encodePacked(remoteAddress_, address(this)); emit SetTrustedRemoteAddress(remoteChainId_, remoteAddress_); } /// @notice Sets precrime address function setPrecrime(address precrime_) external onlyRole("bridge_admin") { precrime = precrime_; emit SetPrecrime(precrime_); } /// @notice Activate or deactivate the bridge function setBridgeStatus(bool isActive_) external onlyRole("bridge_admin") { bridgeActive = isActive_; emit BridgeStatusSet(isActive_); } // ========= View Functions ========= // /// @notice Gets endpoint config for this contract function getConfig( uint16 version_, uint16 chainId_, address, uint256 configType_ ) external view returns (bytes memory) { return lzEndpoint.getConfig(version_, chainId_, address(this), configType_); } /// @notice Get trusted remote for the given chain as an function getTrustedRemoteAddress(uint16 remoteChainId_) external view returns (bytes memory) { bytes memory path = trustedRemoteLookup[remoteChainId_]; if (path.length == 0) revert Bridge_NoTrustedPath(); // The last 20 bytes should be address(this) return path.slice(0, path.length - 20); } function isTrustedRemote( uint16 srcChainId_, bytes calldata srcAddress_ ) external view returns (bool) { bytes memory trustedSource = trustedRemoteLookup[srcChainId_]; if (srcAddress_.length == 0 || trustedSource.length == 0) revert Bridge_TrustedRemoteUninitialized(); return (srcAddress_.length == trustedSource.length && keccak256(srcAddress_) == keccak256(trustedSource)); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface ILayerZeroUserApplicationConfig { // @notice set the configuration of the LayerZero messaging library of the specified version // @param _version - messaging library version // @param _chainId - the chainId for the pending config change // @param _configType - type of configuration. every messaging library has its own convention. // @param _config - configuration in the bytes. can encode arbitrary content. function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external; // @notice set the send() LayerZero messaging library version to _version // @param _version - new messaging library version function setSendVersion(uint16 _version) external; // @notice set the lzReceive() LayerZero messaging library version to _version // @param _version - new messaging library version function setReceiveVersion(uint16 _version) external; // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload // @param _srcChainId - the chainId of the source chain // @param _srcAddress - the contract address of the source contract at the source chain function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; import "./ILayerZeroUserApplicationConfig.sol"; interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig { // @notice send a LayerZero message to the specified address at a LayerZero endpoint. // @param _dstChainId - the destination chain identifier // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains // @param _payload - a custom bytes payload to send to the destination contract // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable; // @notice used by the messaging library to publish verified payload // @param _srcChainId - the source chain identifier // @param _srcAddress - the source contract (as bytes) at the source chain // @param _dstAddress - the address on destination chain // @param _nonce - the unbound message ordering nonce // @param _gasLimit - the gas limit for external contract execution // @param _payload - verified payload to send to the destination contract function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external; // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain // @param _srcChainId - the source chain identifier // @param _srcAddress - the source chain contract address function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64); // @notice get the outboundNonce from this source chain which, consequently, is always an EVM // @param _srcAddress - the source chain contract address function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64); // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery // @param _dstChainId - the destination chain identifier // @param _userApplication - the user app address on this EVM chain // @param _payload - the custom message to send over LayerZero // @param _payInZRO - if false, user app pays the protocol fee in native token // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee); // @notice get this Endpoint's immutable source identifier function getChainId() external view returns (uint16); // @notice the interface to retry failed message on this Endpoint destination // @param _srcChainId - the source chain identifier // @param _srcAddress - the source chain contract address // @param _payload - the payload to be retried function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external; // @notice query if any STORED payload (message blocking) at the endpoint. // @param _srcChainId - the source chain identifier // @param _srcAddress - the source chain contract address function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool); // @notice query if the _libraryAddress is valid for sending msgs. // @param _userApplication - the user app address on this EVM chain function getSendLibraryAddress(address _userApplication) external view returns (address); // @notice query if the _libraryAddress is valid for receiving msgs. // @param _userApplication - the user app address on this EVM chain function getReceiveLibraryAddress(address _userApplication) external view returns (address); // @notice query if the non-reentrancy guard for send() is on // @return true if the guard is on. false otherwise function isSendingPayload() external view returns (bool); // @notice query if the non-reentrancy guard for receive() is on // @return true if the guard is on. false otherwise function isReceivingPayload() external view returns (bool); // @notice get the configuration of the LayerZero messaging library of the specified version // @param _version - messaging library version // @param _chainId - the chainId for the pending config change // @param _userApplication - the contract address of the user application // @param _configType - type of configuration. every messaging library has its own convention. function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory); // @notice get the send() LayerZero messaging library version // @param _userApplication - the contract address of the user application function getSendVersion(address _userApplication) external view returns (uint16); // @notice get the lzReceive() LayerZero messaging library version // @param _userApplication - the contract address of the user application function getReceiveVersion(address _userApplication) external view returns (uint16); }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface ILayerZeroReceiver { // @notice LayerZero endpoint will invoke this function to deliver the message on the destination // @param _srcChainId - the source endpoint identifier // @param _srcAddress - the source sending contract address from the source chain // @param _nonce - the ordered message nonce // @param _payload - the signed payload is the UA bytes has encoded to be sent function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external; }
// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.15; import {ROLESv1} from "src/modules/ROLES/ROLES.v1.sol"; import "src/Kernel.sol"; /// @notice Abstract contract to have the `onlyRole` modifier /// @dev Inheriting this automatically makes ROLES module a dependency abstract contract RolesConsumer { ROLESv1 public ROLES; modifier onlyRole(bytes32 role_) { ROLES.requireRole(role_, msg.sender); _; } } /// @notice Module that holds multisig roles needed by various policies. contract OlympusRoles is ROLESv1 { //============================================================================================// // MODULE SETUP // //============================================================================================// constructor(Kernel kernel_) Module(kernel_) {} /// @inheritdoc Module function KEYCODE() public pure override returns (Keycode) { return toKeycode("ROLES"); } /// @inheritdoc Module function VERSION() external pure override returns (uint8 major, uint8 minor) { major = 1; minor = 0; } //============================================================================================// // CORE FUNCTIONS // //============================================================================================// /// @inheritdoc ROLESv1 function saveRole(bytes32 role_, address addr_) external override permissioned { if (hasRole[addr_][role_]) revert ROLES_AddressAlreadyHasRole(addr_, role_); ensureValidRole(role_); // Grant role to the address hasRole[addr_][role_] = true; emit RoleGranted(role_, addr_); } /// @inheritdoc ROLESv1 function removeRole(bytes32 role_, address addr_) external override permissioned { if (!hasRole[addr_][role_]) revert ROLES_AddressDoesNotHaveRole(addr_, role_); hasRole[addr_][role_] = false; emit RoleRevoked(role_, addr_); } //============================================================================================// // VIEW FUNCTIONS // //============================================================================================// /// @inheritdoc ROLESv1 function requireRole(bytes32 role_, address caller_) external view override { if (!hasRole[caller_][role_]) revert ROLES_RequireRole(role_); } /// @inheritdoc ROLESv1 function ensureValidRole(bytes32 role_) public pure override { for (uint256 i = 0; i < 32; ) { bytes1 char = role_[i]; if ((char < 0x61 || char > 0x7A) && char != 0x5f && char != 0x00) { revert ROLES_InvalidRole(role_); // a-z only } unchecked { i++; } } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.15; import "src/Kernel.sol"; abstract contract ROLESv1 is Module { // ========= EVENTS ========= // event RoleGranted(bytes32 indexed role_, address indexed addr_); event RoleRevoked(bytes32 indexed role_, address indexed addr_); // ========= ERRORS ========= // error ROLES_InvalidRole(bytes32 role_); error ROLES_RequireRole(bytes32 role_); error ROLES_AddressAlreadyHasRole(address addr_, bytes32 role_); error ROLES_AddressDoesNotHaveRole(address addr_, bytes32 role_); error ROLES_RoleDoesNotExist(bytes32 role_); // ========= STATE ========= // /// @notice Mapping for if an address has a policy-defined role. mapping(address => mapping(bytes32 => bool)) public hasRole; // ========= FUNCTIONS ========= // /// @notice Function to grant policy-defined roles to some address. Can only be called by admin. function saveRole(bytes32 role_, address addr_) external virtual; /// @notice Function to revoke policy-defined roles from some address. Can only be called by admin. function removeRole(bytes32 role_, address addr_) external virtual; /// @notice "Modifier" to restrict policy function access to certain addresses with a role. /// @dev Roles are defined in the policy and granted by the ROLES admin. function requireRole(bytes32 role_, address caller_) external virtual; /// @notice Function that checks if role is valid (all lower case) function ensureValidRole(bytes32 role_) external pure virtual; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.15; import {OlympusERC20Token as OHM} from "src/external/OlympusERC20.sol"; import "src/Kernel.sol"; /// @notice Wrapper for minting and burning functions of OHM token. abstract contract MINTRv1 is Module { // ========= EVENTS ========= // event IncreaseMintApproval(address indexed policy_, uint256 newAmount_); event DecreaseMintApproval(address indexed policy_, uint256 newAmount_); event Mint(address indexed policy_, address indexed to_, uint256 amount_); event Burn(address indexed policy_, address indexed from_, uint256 amount_); // ========= ERRORS ========= // error MINTR_NotApproved(); error MINTR_ZeroAmount(); error MINTR_NotActive(); // ========= STATE ========= // OHM public ohm; /// @notice Status of the minter. If false, minting and burning OHM is disabled. bool public active; /// @notice Mapping of who is approved for minting. /// @dev minter -> amount. Infinite approval is max(uint256). mapping(address => uint256) public mintApproval; // ========= FUNCTIONS ========= // modifier onlyWhileActive() { if (!active) revert MINTR_NotActive(); _; } /// @notice Mint OHM to an address. function mintOhm(address to_, uint256 amount_) external virtual; /// @notice Burn OHM from an address. Must have approval. function burnOhm(address from_, uint256 amount_) external virtual; /// @notice Increase approval for specific withdrawer addresses /// @dev Policies must explicity request how much they want approved before withdrawing. function increaseMintApproval(address policy_, uint256 amount_) external virtual; /// @notice Decrease approval for specific withdrawer addresses function decreaseMintApproval(address policy_, uint256 amount_) external virtual; /// @notice Emergency shutdown of minting and burning. function deactivate() external virtual; /// @notice Re-activate minting and burning after shutdown. function activate() external virtual; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.15; // ███████ █████ █████ █████ ██████ ██████ ███████████ █████ █████ █████████ // ███░░░░░███ ░░███ ░░███ ░░███ ░░██████ ██████ ░░███░░░░░███░░███ ░░███ ███░░░░░███ // ███ ░░███ ░███ ░░███ ███ ░███░█████░███ ░███ ░███ ░███ ░███ ░███ ░░░ // ░███ ░███ ░███ ░░█████ ░███░░███ ░███ ░██████████ ░███ ░███ ░░█████████ // ░███ ░███ ░███ ░░███ ░███ ░░░ ░███ ░███░░░░░░ ░███ ░███ ░░░░░░░░███ // ░░███ ███ ░███ █ ░███ ░███ ░███ ░███ ░███ ░███ ███ ░███ // ░░░███████░ ███████████ █████ █████ █████ █████ ░░████████ ░░█████████ // ░░░░░░░ ░░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░░░░ ░░░░░░░░░ //============================================================================================// // GLOBAL TYPES // //============================================================================================// /// @notice Actions to trigger state changes in the kernel. Passed by the executor enum Actions { InstallModule, UpgradeModule, ActivatePolicy, DeactivatePolicy, ChangeExecutor, MigrateKernel } /// @notice Used by executor to select an action and a target contract for a kernel action struct Instruction { Actions action; address target; } /// @notice Used to define which module functions a policy needs access to struct Permissions { Keycode keycode; bytes4 funcSelector; } type Keycode is bytes5; //============================================================================================// // UTIL FUNCTIONS // //============================================================================================// error TargetNotAContract(address target_); error InvalidKeycode(Keycode keycode_); // solhint-disable-next-line func-visibility function toKeycode(bytes5 keycode_) pure returns (Keycode) { return Keycode.wrap(keycode_); } // solhint-disable-next-line func-visibility function fromKeycode(Keycode keycode_) pure returns (bytes5) { return Keycode.unwrap(keycode_); } // solhint-disable-next-line func-visibility function ensureContract(address target_) view { if (target_.code.length == 0) revert TargetNotAContract(target_); } // solhint-disable-next-line func-visibility function ensureValidKeycode(Keycode keycode_) pure { bytes5 unwrapped = Keycode.unwrap(keycode_); for (uint256 i = 0; i < 5; ) { bytes1 char = unwrapped[i]; if (char < 0x41 || char > 0x5A) revert InvalidKeycode(keycode_); // A-Z only unchecked { i++; } } } //============================================================================================// // COMPONENTS // //============================================================================================// /// @notice Generic adapter interface for kernel access in modules and policies. abstract contract KernelAdapter { error KernelAdapter_OnlyKernel(address caller_); Kernel public kernel; constructor(Kernel kernel_) { kernel = kernel_; } /// @notice Modifier to restrict functions to be called only by kernel. modifier onlyKernel() { if (msg.sender != address(kernel)) revert KernelAdapter_OnlyKernel(msg.sender); _; } /// @notice Function used by kernel when migrating to a new kernel. function changeKernel(Kernel newKernel_) external onlyKernel { kernel = newKernel_; } } /// @notice Base level extension of the kernel. Modules act as independent state components to be /// interacted with and mutated through policies. /// @dev Modules are installed and uninstalled via the executor. abstract contract Module is KernelAdapter { error Module_PolicyNotPermitted(address policy_); constructor(Kernel kernel_) KernelAdapter(kernel_) {} /// @notice Modifier to restrict which policies have access to module functions. modifier permissioned() { if ( msg.sender == address(kernel) || !kernel.modulePermissions(KEYCODE(), Policy(msg.sender), msg.sig) ) revert Module_PolicyNotPermitted(msg.sender); _; } /// @notice 5 byte identifier for a module. function KEYCODE() public pure virtual returns (Keycode) {} /// @notice Returns which semantic version of a module is being implemented. /// @return major - Major version upgrade indicates breaking change to the interface. /// @return minor - Minor version change retains backward-compatible interface. function VERSION() external pure virtual returns (uint8 major, uint8 minor) {} /// @notice Initialization function for the module /// @dev This function is called when the module is installed or upgraded by the kernel. /// @dev MUST BE GATED BY onlyKernel. Used to encompass any initialization or upgrade logic. function INIT() external virtual onlyKernel {} } /// @notice Policies are application logic and external interface for the kernel and installed modules. /// @dev Policies are activated and deactivated in the kernel by the executor. /// @dev Module dependencies and function permissions must be defined in appropriate functions. abstract contract Policy is KernelAdapter { error Policy_ModuleDoesNotExist(Keycode keycode_); constructor(Kernel kernel_) KernelAdapter(kernel_) {} /// @notice Easily accessible indicator for if a policy is activated or not. function isActive() external view returns (bool) { return kernel.isPolicyActive(this); } /// @notice Function to grab module address from a given keycode. function getModuleAddress(Keycode keycode_) internal view returns (address) { address moduleForKeycode = address(kernel.getModuleForKeycode(keycode_)); if (moduleForKeycode == address(0)) revert Policy_ModuleDoesNotExist(keycode_); return moduleForKeycode; } /// @notice Define module dependencies for this policy. /// @return dependencies - Keycode array of module dependencies. function configureDependencies() external virtual returns (Keycode[] memory dependencies) {} /// @notice Function called by kernel to set module function permissions. /// @return requests - Array of keycodes and function selectors for requested permissions. function requestPermissions() external view virtual returns (Permissions[] memory requests) {} } /// @notice Main contract that acts as a central component registry for the protocol. /// @dev The kernel manages modules and policies. The kernel is mutated via predefined Actions, /// @dev which are input from any address assigned as the executor. The executor can be changed as needed. contract Kernel { // ========= EVENTS ========= // event PermissionsUpdated( Keycode indexed keycode_, Policy indexed policy_, bytes4 funcSelector_, bool granted_ ); event ActionExecuted(Actions indexed action_, address indexed target_); // ========= ERRORS ========= // error Kernel_OnlyExecutor(address caller_); error Kernel_ModuleAlreadyInstalled(Keycode module_); error Kernel_InvalidModuleUpgrade(Keycode module_); error Kernel_PolicyAlreadyActivated(address policy_); error Kernel_PolicyNotActivated(address policy_); // ========= PRIVILEGED ADDRESSES ========= // /// @notice Address that is able to initiate Actions in the kernel. Can be assigned to a multisig or governance contract. address public executor; // ========= MODULE MANAGEMENT ========= // /// @notice Array of all modules currently installed. Keycode[] public allKeycodes; /// @notice Mapping of module address to keycode. mapping(Keycode => Module) public getModuleForKeycode; /// @notice Mapping of keycode to module address. mapping(Module => Keycode) public getKeycodeForModule; /// @notice Mapping of a keycode to all of its policy dependents. Used to efficiently reconfigure policy dependencies. mapping(Keycode => Policy[]) public moduleDependents; /// @notice Helper for module dependent arrays. Prevents the need to loop through array. mapping(Keycode => mapping(Policy => uint256)) public getDependentIndex; /// @notice Module <> Policy Permissions. /// @dev Keycode -> Policy -> Function Selector -> bool for permission mapping(Keycode => mapping(Policy => mapping(bytes4 => bool))) public modulePermissions; // ========= POLICY MANAGEMENT ========= // /// @notice List of all active policies Policy[] public activePolicies; /// @notice Helper to get active policy quickly. Prevents need to loop through array. mapping(Policy => uint256) public getPolicyIndex; //============================================================================================// // CORE FUNCTIONS // //============================================================================================// constructor() { executor = msg.sender; } /// @notice Modifier to check if caller is the executor. modifier onlyExecutor() { if (msg.sender != executor) revert Kernel_OnlyExecutor(msg.sender); _; } function isPolicyActive(Policy policy_) public view returns (bool) { return activePolicies.length > 0 && activePolicies[getPolicyIndex[policy_]] == policy_; } /// @notice Main kernel function. Initiates state changes to kernel depending on Action passed in. function executeAction(Actions action_, address target_) external onlyExecutor { if (action_ == Actions.InstallModule) { ensureContract(target_); ensureValidKeycode(Module(target_).KEYCODE()); _installModule(Module(target_)); } else if (action_ == Actions.UpgradeModule) { ensureContract(target_); ensureValidKeycode(Module(target_).KEYCODE()); _upgradeModule(Module(target_)); } else if (action_ == Actions.ActivatePolicy) { ensureContract(target_); _activatePolicy(Policy(target_)); } else if (action_ == Actions.DeactivatePolicy) { ensureContract(target_); _deactivatePolicy(Policy(target_)); } else if (action_ == Actions.ChangeExecutor) { executor = target_; } else if (action_ == Actions.MigrateKernel) { ensureContract(target_); _migrateKernel(Kernel(target_)); } emit ActionExecuted(action_, target_); } function _installModule(Module newModule_) internal { Keycode keycode = newModule_.KEYCODE(); if (address(getModuleForKeycode[keycode]) != address(0)) revert Kernel_ModuleAlreadyInstalled(keycode); getModuleForKeycode[keycode] = newModule_; getKeycodeForModule[newModule_] = keycode; allKeycodes.push(keycode); newModule_.INIT(); } function _upgradeModule(Module newModule_) internal { Keycode keycode = newModule_.KEYCODE(); Module oldModule = getModuleForKeycode[keycode]; if (address(oldModule) == address(0) || oldModule == newModule_) revert Kernel_InvalidModuleUpgrade(keycode); getKeycodeForModule[oldModule] = Keycode.wrap(bytes5(0)); getKeycodeForModule[newModule_] = keycode; getModuleForKeycode[keycode] = newModule_; newModule_.INIT(); _reconfigurePolicies(keycode); } function _activatePolicy(Policy policy_) internal { if (isPolicyActive(policy_)) revert Kernel_PolicyAlreadyActivated(address(policy_)); // Add policy to list of active policies activePolicies.push(policy_); getPolicyIndex[policy_] = activePolicies.length - 1; // Record module dependencies Keycode[] memory dependencies = policy_.configureDependencies(); uint256 depLength = dependencies.length; for (uint256 i; i < depLength; ) { Keycode keycode = dependencies[i]; moduleDependents[keycode].push(policy_); getDependentIndex[keycode][policy_] = moduleDependents[keycode].length - 1; unchecked { ++i; } } // Grant permissions for policy to access restricted module functions Permissions[] memory requests = policy_.requestPermissions(); _setPolicyPermissions(policy_, requests, true); } function _deactivatePolicy(Policy policy_) internal { if (!isPolicyActive(policy_)) revert Kernel_PolicyNotActivated(address(policy_)); // Revoke permissions Permissions[] memory requests = policy_.requestPermissions(); _setPolicyPermissions(policy_, requests, false); // Remove policy from all policy data structures uint256 idx = getPolicyIndex[policy_]; Policy lastPolicy = activePolicies[activePolicies.length - 1]; activePolicies[idx] = lastPolicy; activePolicies.pop(); getPolicyIndex[lastPolicy] = idx; delete getPolicyIndex[policy_]; // Remove policy from module dependents _pruneFromDependents(policy_); } /// @notice All functionality will move to the new kernel. WARNING: ACTION WILL BRICK THIS KERNEL. /// @dev New kernel must add in all of the modules and policies via executeAction. /// @dev NOTE: Data does not get cleared from this kernel. function _migrateKernel(Kernel newKernel_) internal { uint256 keycodeLen = allKeycodes.length; for (uint256 i; i < keycodeLen; ) { Module module = Module(getModuleForKeycode[allKeycodes[i]]); module.changeKernel(newKernel_); unchecked { ++i; } } uint256 policiesLen = activePolicies.length; for (uint256 j; j < policiesLen; ) { Policy policy = activePolicies[j]; // Deactivate before changing kernel policy.changeKernel(newKernel_); unchecked { ++j; } } } function _reconfigurePolicies(Keycode keycode_) internal { Policy[] memory dependents = moduleDependents[keycode_]; uint256 depLength = dependents.length; for (uint256 i; i < depLength; ) { dependents[i].configureDependencies(); unchecked { ++i; } } } function _setPolicyPermissions( Policy policy_, Permissions[] memory requests_, bool grant_ ) internal { uint256 reqLength = requests_.length; for (uint256 i = 0; i < reqLength; ) { Permissions memory request = requests_[i]; modulePermissions[request.keycode][policy_][request.funcSelector] = grant_; emit PermissionsUpdated(request.keycode, policy_, request.funcSelector, grant_); unchecked { ++i; } } } function _pruneFromDependents(Policy policy_) internal { Keycode[] memory dependencies = policy_.configureDependencies(); uint256 depcLength = dependencies.length; for (uint256 i; i < depcLength; ) { Keycode keycode = dependencies[i]; Policy[] storage dependents = moduleDependents[keycode]; uint256 origIndex = getDependentIndex[keycode][policy_]; Policy lastPolicy = dependents[dependents.length - 1]; // Swap with last and pop dependents[origIndex] = lastPolicy; dependents.pop(); // Record new index and delete deactivated policy index getDependentIndex[keycode][lastPolicy] = origIndex; delete getDependentIndex[keycode][policy_]; unchecked { ++i; } } } }
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity >=0.7.5; /// @notice Olympus OHM token /// @dev This contract is the legacy v2 OHM token. Included in the repo for completeness, /// since it is not being changed and is imported in some contracts. interface IOlympusAuthority { // ========= EVENTS ========= // event GovernorPushed(address indexed from, address indexed to, bool _effectiveImmediately); event GuardianPushed(address indexed from, address indexed to, bool _effectiveImmediately); event PolicyPushed(address indexed from, address indexed to, bool _effectiveImmediately); event VaultPushed(address indexed from, address indexed to, bool _effectiveImmediately); event GovernorPulled(address indexed from, address indexed to); event GuardianPulled(address indexed from, address indexed to); event PolicyPulled(address indexed from, address indexed to); event VaultPulled(address indexed from, address indexed to); // ========= VIEW ========= // function governor() external view returns (address); function guardian() external view returns (address); function policy() external view returns (address); function vault() external view returns (address); } // File: types/OlympusAccessControlled.sol abstract contract OlympusAccessControlled { // ========= EVENTS ========= // event AuthorityUpdated(IOlympusAuthority indexed authority); string internal UNAUTHORIZED = "UNAUTHORIZED"; // save gas // ========= STATE VARIABLES ========= // IOlympusAuthority public authority; // ========= Constructor ========= // constructor(IOlympusAuthority _authority) { authority = _authority; emit AuthorityUpdated(_authority); } // ========= MODIFIERS ========= // modifier onlyGovernor() { require(msg.sender == authority.governor(), UNAUTHORIZED); _; } modifier onlyGuardian() { require(msg.sender == authority.guardian(), UNAUTHORIZED); _; } modifier onlyPermitted() { require(msg.sender == authority.policy(), UNAUTHORIZED); _; } modifier onlyVault() { require(msg.sender == authority.vault(), UNAUTHORIZED); _; } // ========= GOV ONLY ========= // function setAuthority(IOlympusAuthority _newAuthority) external onlyGovernor { authority = _newAuthority; emit AuthorityUpdated(_newAuthority); } } // File: cryptography/ECDSA.sol /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } else if (error == RecoverError.InvalidSignatureV) { revert("ECDSA: invalid signature 'v' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { // Check the signature length // - case 65: r,s,v signature (standard) // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else if (signature.length == 64) { bytes32 r; bytes32 vs; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) vs := mload(add(signature, 0x40)) } return tryRecover(hash, r, vs); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s; uint8 v; assembly { s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) v := add(shr(255, vs), 27) } return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } if (v != 27 && v != 28) { return (address(0), RecoverError.InvalidSignatureV); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } } // File: cryptography/EIP712.sol /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ */ abstract contract EIP712 { /* solhint-disable var-name-mixedcase */ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; uint256 private immutable _CACHED_CHAIN_ID; bytes32 private immutable _HASHED_NAME; bytes32 private immutable _HASHED_VERSION; bytes32 private immutable _TYPE_HASH; /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { uint256 chainID; assembly { chainID := chainid() } bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); bytes32 typeHash = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; _CACHED_CHAIN_ID = chainID; _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion); _TYPE_HASH = typeHash; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { uint256 chainID; assembly { chainID := chainid() } if (chainID == _CACHED_CHAIN_ID) { return _CACHED_DOMAIN_SEPARATOR; } else { return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION); } } function _buildDomainSeparator( bytes32 typeHash, bytes32 nameHash, bytes32 versionHash ) private view returns (bytes32) { uint256 chainID; assembly { chainID := chainid() } return keccak256(abi.encode(typeHash, nameHash, versionHash, chainID, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); } } // File: interfaces/IERC20Permit.sol /** * @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 IERC20Permit { /** * @dev Sets `value` as th xe 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); } // File: interfaces/IERC20.sol interface IERC20 { /** * @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 `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount ) external returns (bool); /** * @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); } // File: interfaces/IOHM.sol interface IOHM is IERC20 { function mint(address account_, uint256 amount_) external; function burn(uint256 amount) external; function burnFrom(address account_, uint256 amount_) external; } // File: libraries/SafeMath.sol library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; assert(a == b * c + (a % b)); // There is no case in which this doesn't hold return c; } // Only used in the BondingCalculator.sol function sqrrt(uint256 a) internal pure returns (uint256 c) { if (a > 3) { c = a; uint256 b = add(div(a, 2), 1); while (b < c) { c = b; b = div(add(div(a, b), b), 2); } } else if (a != 0) { c = 1; } } } // File: libraries/Counters.sol library Counters { using SafeMath for uint256; struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { // The {SafeMath} overflow check can be skipped here, see the comment at the top counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } } // File: types/ERC20.sol abstract contract ERC20 is IERC20 { using SafeMath for uint256; // TODO comment actual hash value. bytes32 private constant ERC20TOKEN_ERC1820_INTERFACE_ID = keccak256("ERC20Token"); mapping(address => uint256) internal _balances; mapping(address => mapping(address => uint256)) internal _allowances; uint256 internal _totalSupply; string internal _name; string internal _symbol; uint8 internal immutable _decimals; constructor( string memory name_, string memory symbol_, uint8 decimals_ ) { _name = name_; _symbol = symbol_; _decimals = decimals_; } function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public view virtual returns (uint8) { return _decimals; } function totalSupply() public view override returns (uint256) { return _totalSupply; } function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(msg.sender, recipient, amount); return true; } function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(msg.sender, spender, amount); return true; } function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve( sender, msg.sender, _allowances[sender][msg.sender].sub(amount, "ERC20: transfer amount exceeds allowance") ); return true; } function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)); return true; } function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve( msg.sender, spender, _allowances[msg.sender][spender].sub( subtractedValue, "ERC20: decreased allowance below zero" ) ); return true; } function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } function _beforeTokenTransfer( address from_, address to_, uint256 amount_ ) internal virtual {} } // File: types/ERC20Permit.sol /** * @dev Implementation 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. * * _Available since v3.4._ */ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { using Counters for Counters.Counter; mapping(address => Counters.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private immutable _PERMIT_TYPEHASH = keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ); /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC20 token name. */ constructor(string memory name) EIP712(name, "1") {} /** * @dev See {IERC20Permit-permit}. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256( abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline) ); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _approve(owner, spender, value); } /** * @dev See {IERC20Permit-nonces}. */ function nonces(address owner) public view virtual override returns (uint256) { return _nonces[owner].current(); } /** * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } /** * @dev "Consume a nonce": return the current value and increment. * * _Available since v4.1._ */ function _useNonce(address owner) internal virtual returns (uint256 current) { Counters.Counter storage nonce = _nonces[owner]; current = nonce.current(); nonce.increment(); } } // File: OlympusERC20.sol contract OlympusERC20Token is ERC20Permit, IOHM, OlympusAccessControlled { using SafeMath for uint256; constructor(address _authority) ERC20("Olympus", "OHM", 9) ERC20Permit("Olympus") OlympusAccessControlled(IOlympusAuthority(_authority)) {} function mint(address account_, uint256 amount_) external override onlyVault { _mint(account_, amount_); } function burn(uint256 amount) external override { _burn(msg.sender, amount); } function burnFrom(address account_, uint256 amount_) external override { _burnFrom(account_, amount_); } function _burnFrom(address account_, uint256 amount_) internal { uint256 decreasedAllowance_ = allowance(account_, msg.sender).sub( amount_, "ERC20: burn amount exceeds allowance" ); _approve(account_, msg.sender, decreasedAllowance_); _burn(account_, amount_); } }
{ "remappings": [ "@openzeppelin/=lib/openzeppelin-contracts/", "balancer-v2/=lib/balancer-v2/", "bonds/=lib/bonds/src/", "ds-test/=lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "interfaces/=src/interfaces/", "layer-zero/=lib/solidity-examples/contracts/", "libraries/=src/libraries/", "modules/=src/modules/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "policies/=src/policies/", "solidity-examples/=lib/solidity-examples/contracts/", "solmate/=lib/solmate/src/", "test/=src/test/" ], "optimizer": { "enabled": true, "runs": 10 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract Kernel","name":"kernel_","type":"address"},{"internalType":"address","name":"endpoint_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Bridge_Deactivated","type":"error"},{"inputs":[],"name":"Bridge_DestinationNotTrusted","type":"error"},{"inputs":[],"name":"Bridge_InsufficientAmount","type":"error"},{"inputs":[],"name":"Bridge_InvalidCaller","type":"error"},{"inputs":[],"name":"Bridge_InvalidMessageSource","type":"error"},{"inputs":[],"name":"Bridge_InvalidPayload","type":"error"},{"inputs":[],"name":"Bridge_NoStoredMessage","type":"error"},{"inputs":[],"name":"Bridge_NoTrustedPath","type":"error"},{"inputs":[],"name":"Bridge_TrustedRemoteUninitialized","type":"error"},{"inputs":[{"internalType":"address","name":"caller_","type":"address"}],"name":"KernelAdapter_OnlyKernel","type":"error"},{"inputs":[{"internalType":"Keycode","name":"keycode_","type":"bytes5"}],"name":"Policy_ModuleDoesNotExist","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver_","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"},{"indexed":true,"internalType":"uint16","name":"srcChain_","type":"uint16"}],"name":"BridgeReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isActive_","type":"bool"}],"name":"BridgeStatusSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender_","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"},{"indexed":true,"internalType":"uint16","name":"dstChain_","type":"uint16"}],"name":"BridgeTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"srcChainId_","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"srcAddress_","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"nonce_","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"payload_","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"reason_","type":"bytes"}],"name":"MessageFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"srcChainId_","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"srcAddress_","type":"bytes"},{"indexed":false,"internalType":"uint64","name":"nonce_","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"payloadHash_","type":"bytes32"}],"name":"RetryMessageSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"dstChainId_","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"type_","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"_minDstGas","type":"uint256"}],"name":"SetMinDstGas","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"precrime_","type":"address"}],"name":"SetPrecrime","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"remoteChainId_","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"path_","type":"bytes"}],"name":"SetTrustedRemote","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"remoteChainId_","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"remoteAddress_","type":"bytes"}],"name":"SetTrustedRemoteAddress","type":"event"},{"inputs":[],"name":"MINTR","outputs":[{"internalType":"contract MINTRv1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLES","outputs":[{"internalType":"contract ROLESv1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bridgeActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Kernel","name":"newKernel_","type":"address"}],"name":"changeKernel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"configureDependencies","outputs":[{"internalType":"Keycode[]","name":"dependencies","type":"bytes5[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"dstChainId_","type":"uint16"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bytes","name":"adapterParams_","type":"bytes"}],"name":"estimateSendFee","outputs":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"zroFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint64","name":"","type":"uint64"}],"name":"failedMessages","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId_","type":"uint16"},{"internalType":"bytes","name":"srcAddress_","type":"bytes"}],"name":"forceResumeReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version_","type":"uint16"},{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"configType_","type":"uint256"}],"name":"getConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"remoteChainId_","type":"uint16"}],"name":"getTrustedRemoteAddress","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId_","type":"uint16"},{"internalType":"bytes","name":"srcAddress_","type":"bytes"}],"name":"isTrustedRemote","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kernel","outputs":[{"internalType":"contract Kernel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lzEndpoint","outputs":[{"internalType":"contract ILayerZeroEndpoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId_","type":"uint16"},{"internalType":"bytes","name":"srcAddress_","type":"bytes"},{"internalType":"uint64","name":"nonce_","type":"uint64"},{"internalType":"bytes","name":"payload_","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ohm","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"precrime","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId_","type":"uint16"},{"internalType":"bytes","name":"srcAddress_","type":"bytes"},{"internalType":"uint64","name":"nonce_","type":"uint64"},{"internalType":"bytes","name":"payload_","type":"bytes"}],"name":"receiveMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestPermissions","outputs":[{"components":[{"internalType":"Keycode","name":"keycode","type":"bytes5"},{"internalType":"bytes4","name":"funcSelector","type":"bytes4"}],"internalType":"struct Permissions[]","name":"permissions","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId_","type":"uint16"},{"internalType":"bytes","name":"srcAddress_","type":"bytes"},{"internalType":"uint64","name":"nonce_","type":"uint64"},{"internalType":"bytes","name":"payload_","type":"bytes"}],"name":"retryMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"dstChainId_","type":"uint16"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"sendOhm","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bool","name":"isActive_","type":"bool"}],"name":"setBridgeStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version_","type":"uint16"},{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"uint256","name":"configType_","type":"uint256"},{"internalType":"bytes","name":"config_","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"precrime_","type":"address"}],"name":"setPrecrime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version_","type":"uint16"}],"name":"setReceiveVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version_","type":"uint16"}],"name":"setSendVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId_","type":"uint16"},{"internalType":"bytes","name":"path_","type":"bytes"}],"name":"setTrustedRemote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"remoteChainId_","type":"uint16"},{"internalType":"bytes","name":"remoteAddress_","type":"bytes"}],"name":"setTrustedRemoteAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"trustedRemoteLookup","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b5060405162002c2b38038062002c2b833981016040819052620000349162000088565b600080546001600160a01b039384166001600160a01b0319909116179055166080526003805460ff60a01b1916600160a01b179055620000c7565b6001600160a01b03811681146200008557600080fd5b50565b600080604083850312156200009c57600080fd5b8251620000a9816200006f565b6020840151909250620000bc816200006f565b809150509250929050565b608051612b106200011b6000396000818161045b0152818161057c015281816108a40152818161099901528181610a1101528181610e450152818161164601528181611a170152611b640152612b106000f3fe6080604052600436106101515760003560e01c80621d35671461015657806302b1d2391461017857806307e0db17146101ae57806310ddb137146101ce5780631b2083dc146101ee57806322f3e2d4146102235780632556e453146102485780633d8b38f61461025b57806342d65a8d1461027b5780634657b36c1461029b578063577de7d0146102bb5780635924be70146102db5780635b8c41e6146102fd5780636edb3d3c1461035a5780637533d7881461037a578063923cb952146103a75780639459b875146103c7578063950c8a74146103e95780639f38369a14610409578063a6c3d16514610429578063b353aaa714610449578063baf3292d1461047d578063cbed8b9c1461049d578063d1deba1f146104bd578063d4aae0c4146104d0578063d58a8483146104f0578063ead93c8f14610510578063eb8d72b714610531578063f5ecbdbc14610551575b600080fd5b34801561016257600080fd5b50610176610171366004611f38565b610571565b005b34801561018457600080fd5b50600354610198906001600160a01b031681565b6040516101a59190611fcb565b60405180910390f35b3480156101ba57600080fd5b506101766101c9366004611fdf565b61081a565b3480156101da57600080fd5b506101766101e9366004611fdf565b61090f565b3480156101fa57600080fd5b5061020e610209366004612012565b6109d2565b604080519283526020830191909152016101a5565b34801561022f57600080fd5b50610238610aa0565b60405190151581526020016101a5565b610176610256366004612082565b610b17565b34801561026757600080fd5b506102386102763660046120c1565b610cb8565b34801561028757600080fd5b506101766102963660046120c1565b610dbd565b3480156102a757600080fd5b506101766102b6366004612113565b610eb8565b3480156102c757600080fd5b50600254610198906001600160a01b031681565b3480156102e757600080fd5b506102f0610f10565b6040516101a59190612130565b34801561030957600080fd5b5061034c610318366004612256565b6004602090815260009384526040808520845180860184018051928152908401958401959095209452929052825290205481565b6040519081526020016101a5565b34801561036657600080fd5b506101766103753660046122b3565b6110af565b34801561038657600080fd5b5061039a610395366004611fdf565b6110e1565b6040516101a5919061238f565b3480156103b357600080fd5b50600154610198906001600160a01b031681565b3480156103d357600080fd5b506103dc61117b565b6040516101a591906123a2565b3480156103f557600080fd5b50600654610198906001600160a01b031681565b34801561041557600080fd5b5061039a610424366004611fdf565b611318565b34801561043557600080fd5b506101766104443660046120c1565b6113ff565b34801561045557600080fd5b506101987f000000000000000000000000000000000000000000000000000000000000000081565b34801561048957600080fd5b50610176610498366004612113565b6114f4565b3480156104a957600080fd5b506101766104b83660046123f0565b6115be565b6101766104cb366004611f38565b6116bf565b3480156104dc57600080fd5b50600054610198906001600160a01b031681565b3480156104fc57600080fd5b5061017661050b36600461242d565b611861565b34801561051c57600080fd5b5060035461023890600160a01b900460ff1681565b34801561053d57600080fd5b5061017661054c3660046120c1565b611921565b34801561055d57600080fd5b5061039a61056c36600461244a565b6119e6565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105ba576040516395946b5d60e01b815260040160405180910390fd5b61ffff8616600090815260056020526040812080546105d890612497565b80601f016020809104026020016040519081016040528092919081815260200182805461060490612497565b80156106515780601f1061062657610100808354040283529160200191610651565b820191906000526020600020905b81548152906001019060200180831161063457829003601f168201915b50505050509050805160001480610669575080518514155b8061069157508051602082012060405161068690889088906124d1565b604051809103902014155b156106af57604051634488ea9760e11b815260040160405180910390fd5b600080306001600160a01b0316636edb3d3c60e01b8a8a8a8a8a8a6040516024016106df9695949392919061250a565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161071d9190612557565b6000604051808303816000865af19150503d806000811461075a576040519150601f19603f3d011682016040523d82523d6000602084013e61075f565b606091505b50915091508161080f5784846040516107799291906124d1565b6040805191829003822061ffff8c16600090815260046020529190912090916107a5908b908b906124d1565b9081526040805191829003602090810183206001600160401b038b166000908152915220919091557fe183f33de2837795525b4792ca4cd60535bd77c53b7e7030060bfcf5734d6b0c90610806908b908b908b908b908b908b908990612573565b60405180910390a15b505050505050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061085b90849033906004016125d5565b600060405180830381600087803b15801561087557600080fd5b505af1158015610889573d6000803e3d6000fd5b50506040516307e0db1760e01b815261ffff851660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692506307e0db1791506024015b600060405180830381600087803b1580156108f357600080fd5b505af1158015610907573d6000803e3d6000fd5b505050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061095090849033906004016125d5565b600060405180830381600087803b15801561096a57600080fd5b505af115801561097e573d6000803e3d6000fd5b50506040516310ddb13760e01b815261ffff851660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692506310ddb13791506024016108d9565b600080600086866040516020016109ea9291906125ec565b60408051601f198184030181529082905263040a7bb160e41b825291506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340a7bb1090610a51908b90309086906000908c908c90600401612605565b6040805180830381865afa158015610a6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a91919061264e565b92509250509550959350505050565b6000805460405163e52223bb60e01b81526001600160a01b039091169063e52223bb90610ad1903090600401611fcb565b602060405180830381865afa158015610aee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b129190612672565b905090565b600354600160a01b900460ff16610b4157604051638bfcdf0d60e01b815260040160405180910390fd5b6003546040516370a0823160e01b815282916001600160a01b0316906370a0823190610b71903390600401611fcb565b602060405180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb2919061268f565b1015610bd15760405163ea7aa0c560e01b815260040160405180910390fd5b60008282604051602001610be69291906125ec565b60408051601f198184030181529082905260025463557856ad60e11b83529092506001600160a01b03169063aaf0ad5a90610c2790339086906004016125ec565b600060405180830381600087803b158015610c4157600080fd5b505af1158015610c55573d6000803e3d6000fd5b50505050610c7784823360006040518060200160405280600081525034611a8e565b60405182815261ffff85169033907f39a9310c2653c9e8416b19cc7ef7166640ed10fa3a958f2804c1b3d75f2081019060200160405180910390a350505050565b61ffff831660009081526005602052604081208054829190610cd990612497565b80601f0160208091040260200160405190810160405280929190818152602001828054610d0590612497565b8015610d525780601f10610d2757610100808354040283529160200191610d52565b820191906000526020600020905b815481529060010190602001808311610d3557829003601f168201915b505050505090508383905060001480610d6a57508051155b15610d88576040516302c18f6d60e31b815260040160405180910390fd5b805183148015610db4575080516020820120604051610daa90869086906124d1565b6040518091039020145b95945050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c590610dfe90849033906004016125d5565b600060405180830381600087803b158015610e1857600080fd5b505af1158015610e2c573d6000803e3d6000fd5b50506040516342d65a8d60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692506342d65a8d9150610e80908790879087906004016126a8565b600060405180830381600087803b158015610e9a57600080fd5b505af1158015610eae573d6000803e3d6000fd5b5050505050505050565b6000546001600160a01b03163314610eee573360405163053e900f60e21b8152600401610ee59190611fcb565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b60606000600260009054906101000a90046001600160a01b03166001600160a01b0316631ae7ec2e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8b91906126c6565b60408051600380825260808201909252919250816020015b6040805180820190915260008082526020820152815260200190600190039081610fa3575050604080518082019091526001600160d81b031983168152633a56e30760e01b60208201528151919350908390600090611004576110046126f0565b60200260200101819052506040518060400160405280826001600160d81b031916815260200163aaf0ad5a60e01b6001600160e01b03191681525082600181518110611052576110526126f0565b60200260200101819052506040518060400160405280826001600160d81b031916815260200163359fe78060e01b6001600160e01b031916815250826002815181106110a0576110a06126f0565b60200260200101819052505090565b3330146110cf576040516395946b5d60e01b815260040160405180910390fd5b6110db84848484611be0565b50505050565b600560205260009081526040902080546110fa90612497565b80601f016020809104026020016040519081016040528092919081815260200182805461112690612497565b80156111735780601f1061114857610100808354040283529160200191611173565b820191906000526020600020905b81548152906001019060200180831161115657829003601f168201915b505050505081565b60408051600280825260608083018452926020830190803683370190505090506426a4a72a2960d91b816000815181106111b7576111b76126f0565b6001600160d81b0319909216602092830291909101909101526111df64524f4c455360d81b90565b816001815181106111f2576111f26126f0565b60200260200101906001600160d81b03191690816001600160d81b031916815250506112378160008151811061122a5761122a6126f0565b6020026020010151611d12565b600260006101000a8154816001600160a01b0302191690836001600160a01b031602179055506112738160018151811061122a5761122a6126f0565b600180546001600160a01b0319166001600160a01b03928316179055600254604080516302b1d23960e01b8152905191909216916302b1d2399160048083019260209291908290030181865afa1580156112d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f59190612706565b600380546001600160a01b0319166001600160a01b039290921691909117905590565b61ffff811660009081526005602052604081208054606092919061133b90612497565b80601f016020809104026020016040519081016040528092919081815260200182805461136790612497565b80156113b45780601f10611389576101008083540402835291602001916113b4565b820191906000526020600020905b81548152906001019060200180831161139757829003601f168201915b5050505050905080516000036113dd576040516302fa5b7760e41b815260040160405180910390fd5b6113f86000601483516113f09190612739565b839190611db5565b9392505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061144090849033906004016125d5565b600060405180830381600087803b15801561145a57600080fd5b505af115801561146e573d6000803e3d6000fd5b5050505082823060405160200161148793929190612750565b60408051601f1981840301815291815261ffff86166000908152600560205220906114b290826127d1565b507f8c0400cfe2d1199b1a725c78960bcc2a344d869b80590d0f2bd005db15a572ce8484846040516114e6939291906126a8565b60405180910390a150505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061153590849033906004016125d5565b600060405180830381600087803b15801561154f57600080fd5b505af1158015611563573d6000803e3d6000fd5b5050600680546001600160a01b0319166001600160a01b03861617905550506040517f5db758e995a17ec1ad84bdef7e8c3293a0bd6179bcce400dff5d4c3d87db726b906115b2908490611fcb565b60405180910390a15050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c5906115ff90849033906004016125d5565b600060405180830381600087803b15801561161957600080fd5b505af115801561162d573d6000803e3d6000fd5b50506040516332fb62e760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063cbed8b9c9150611685908990899089908990899060040161288a565b600060405180830381600087803b15801561169f57600080fd5b505af11580156116b3573d6000803e3d6000fd5b50505050505050505050565b61ffff861660009081526004602052604080822090516116e290889088906124d1565b90815260408051602092819003830190206001600160401b038716600090815292529020549050806117275760405163033f21d760e31b815260040160405180910390fd5b8083836040516117389291906124d1565b60405180910390201461175e57604051633d161b8760e11b815260040160405180910390fd5b61ffff8716600090815260046020526040808220905161178190899089906124d1565b90815260408051602092819003830181206001600160401b038916600090815290845282902093909355601f88018290048202830182019052868252611819918991899089908190840183828082843760009201919091525050604080516020601f8a018190048102820181019092528881528a935091508890889081908401838280828437600092019190915250611be092505050565b7fc264d91f3adc5588250e1551f547752ca0cfa8f6b530d243b9f9f4cab10ea8e587878787856040516118509594939291906128c3565b60405180910390a150505050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c5906118a290849033906004016125d5565b600060405180830381600087803b1580156118bc57600080fd5b505af11580156118d0573d6000803e3d6000fd5b505060038054851515600160a01b0260ff60a01b1990911617905550506040517f0c8765b60c3fca0b25c8c97ac199bdf1a16d429abbe4213d48ba4a66d666f241906115b290841515815260200190565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061196290849033906004016125d5565b600060405180830381600087803b15801561197c57600080fd5b505af1158015611990573d6000803e3d6000fd5b5050505061ffff841660009081526005602052604090206119b28385836128fe565b507ffa41487ad5d6728f0b19276fa1eddc16558578f5109fc39d2dc33c3230470dab8484846040516114e6939291906126a8565b604051633d7b2f6f60e21b815261ffff808616600483015284166024820152306044820152606481018290526060907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f5ecbdbc90608401600060405180830381865afa158015611a66573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610db491908101906129b8565b61ffff861660009081526005602052604081208054611aac90612497565b80601f0160208091040260200160405190810160405280929190818152602001828054611ad890612497565b8015611b255780601f10611afa57610100808354040283529160200191611b25565b820191906000526020600020905b815481529060010190602001808311611b0857829003601f168201915b505050505090508051600003611b4e576040516303e334ff60e51b815260040160405180910390fd5b60405162c5803160e81b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c5803100908490611ba5908b9086908c908c908c908c90600401612a25565b6000604051808303818588803b158015611bbe57600080fd5b505af1158015611bd2573d6000803e3d6000fd5b505050505050505050505050565b60008082806020019051810190611bf79190612a7f565b600254604051626b3fcf60e71b81529294509092506001600160a01b03169063359fe78090611c2c90309085906004016125ec565b600060405180830381600087803b158015611c4657600080fd5b505af1158015611c5a573d6000803e3d6000fd5b5050600254604051633a56e30760e01b81526001600160a01b039091169250633a56e3079150611c9090859085906004016125ec565b600060405180830381600087803b158015611caa57600080fd5b505af1158015611cbe573d6000803e3d6000fd5b505050508561ffff16826001600160a01b03167f66e72df5c00d93ba421714963fffa44e34b0f51ad224cd6966565fc089be93f883604051611d0291815260200190565b60405180910390a3505050505050565b60008054604051632d37002d60e21b815282916001600160a01b03169063b4dc00b490611d43908690600401612aad565b602060405180830381865afa158015611d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d849190612706565b90506001600160a01b038116611daf5782604051635c3fa9cd60e01b8152600401610ee59190612aad565b92915050565b606081611dc381601f612ac2565b1015611e025760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610ee5565b611e0c8284612ac2565b84511015611e505760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610ee5565b606082158015611e6f5760405191506000825260208201604052611eb9565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015611ea8578051835260209283019201611e90565b5050858452601f01601f1916604052505b50949350505050565b803561ffff81168114611ed457600080fd5b919050565b60008083601f840112611eeb57600080fd5b5081356001600160401b03811115611f0257600080fd5b602083019150836020828501011115611f1a57600080fd5b9250929050565b80356001600160401b0381168114611ed457600080fd5b60008060008060008060808789031215611f5157600080fd5b611f5a87611ec2565b955060208701356001600160401b0380821115611f7657600080fd5b611f828a838b01611ed9565b9097509550859150611f9660408a01611f21565b94506060890135915080821115611fac57600080fd5b50611fb989828a01611ed9565b979a9699509497509295939492505050565b6001600160a01b0391909116815260200190565b600060208284031215611ff157600080fd5b6113f882611ec2565b6001600160a01b038116811461200f57600080fd5b50565b60008060008060006080868803121561202a57600080fd5b61203386611ec2565b9450602086013561204381611ffa565b93506040860135925060608601356001600160401b0381111561206557600080fd5b61207188828901611ed9565b969995985093965092949392505050565b60008060006060848603121561209757600080fd5b6120a084611ec2565b925060208401356120b081611ffa565b929592945050506040919091013590565b6000806000604084860312156120d657600080fd5b6120df84611ec2565b925060208401356001600160401b038111156120fa57600080fd5b61210686828701611ed9565b9497909650939450505050565b60006020828403121561212557600080fd5b81356113f881611ffa565b602080825282518282018190526000919060409081850190868401855b8281101561218657815180516001600160d81b03191685528601516001600160e01b03191686850152928401929085019060010161214d565b5091979650505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156121d1576121d1612193565b604052919050565b60006001600160401b038211156121f2576121f2612193565b50601f01601f191660200190565b600082601f83011261221157600080fd5b813561222461221f826121d9565b6121a9565b81815284602083860101111561223957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561226b57600080fd5b61227484611ec2565b925060208401356001600160401b0381111561228f57600080fd5b61229b86828701612200565b9250506122aa60408501611f21565b90509250925092565b600080600080608085870312156122c957600080fd5b6122d285611ec2565b935060208501356001600160401b03808211156122ee57600080fd5b6122fa88838901612200565b945061230860408801611f21565b9350606087013591508082111561231e57600080fd5b5061232b87828801612200565b91505092959194509250565b60005b8381101561235257818101518382015260200161233a565b838111156110db5750506000910152565b6000815180845261237b816020860160208601612337565b601f01601f19169290920160200192915050565b6020815260006113f86020830184612363565b6020808252825182820181905260009190848201906040850190845b818110156123e45783516001600160d81b031916835292840192918401916001016123be565b50909695505050505050565b60008060008060006080868803121561240857600080fd5b61241186611ec2565b945061204360208701611ec2565b801515811461200f57600080fd5b60006020828403121561243f57600080fd5b81356113f88161241f565b6000806000806080858703121561246057600080fd5b61246985611ec2565b935061247760208601611ec2565b9250604085013561248781611ffa565b9396929550929360600135925050565b600181811c908216806124ab57607f821691505b6020821081036124cb57634e487b7160e01b600052602260045260246000fd5b50919050565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b61ffff871681526080602082015260006125286080830187896124e1565b6001600160401b0386166040840152828103606084015261254a8185876124e1565b9998505050505050505050565b60008251612569818460208701612337565b9190910192915050565b61ffff8816815260a06020820152600061259160a08301888a6124e1565b6001600160401b038716604084015282810360608401526125b38186886124e1565b905082810360808401526125c78185612363565b9a9950505050505050505050565b9182526001600160a01b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b61ffff871681526001600160a01b038616602082015260a06040820181905260009061263390830187612363565b8515156060840152828103608084015261254a8185876124e1565b6000806040838503121561266157600080fd5b505080516020909101519092909150565b60006020828403121561268457600080fd5b81516113f88161241f565b6000602082840312156126a157600080fd5b5051919050565b61ffff84168152604060208201526000610db46040830184866124e1565b6000602082840312156126d857600080fd5b81516001600160d81b0319811681146113f857600080fd5b634e487b7160e01b600052603260045260246000fd5b60006020828403121561271857600080fd5b81516113f881611ffa565b634e487b7160e01b600052601160045260246000fd5b60008282101561274b5761274b612723565b500390565b8284823760609190911b6001600160601b0319169101908152601401919050565b601f8211156127b757600081815260208120601f850160051c810160208610156127985750805b601f850160051c820191505b81811015610907578281556001016127a4565b505050565b600019600383901b1c191660019190911b1790565b81516001600160401b038111156127ea576127ea612193565b6127fe816127f88454612497565b84612771565b602080601f83116001811461282d576000841561281b5750858301515b61282585826127bc565b865550610907565b600085815260208120601f198616915b8281101561285c5788860151825594840194600190910190840161283d565b508582101561287a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600061ffff8088168352808716602084015250846040830152608060608301526128b86080830184866124e1565b979650505050505050565b61ffff861681526080602082015260006128e16080830186886124e1565b6001600160401b0394909416604083015250606001529392505050565b6001600160401b0383111561291557612915612193565b612929836129238354612497565b83612771565b6000601f84116001811461295757600085156129455750838201355b61294f86826127bc565b8455506129b1565b600083815260209020601f19861690835b828110156129885786850135825560209485019460019092019101612968565b50868210156129a55760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6000602082840312156129ca57600080fd5b81516001600160401b038111156129e057600080fd5b8201601f810184136129f157600080fd5b80516129ff61221f826121d9565b818152856020838501011115612a1457600080fd5b610db4826020830160208601612337565b61ffff8716815260c060208201526000612a4260c0830188612363565b8281036040840152612a548188612363565b6001600160a01b0387811660608601528616608085015283810360a0850152905061254a8185612363565b60008060408385031215612a9257600080fd5b8251612a9d81611ffa565b6020939093015192949293505050565b6001600160d81b031991909116815260200190565b60008219821115612ad557612ad5612723565b50019056fea26469706673582212209f66fcbf215ccd5b466f7bbca94fb27deb3a9915741e80454e6d04704b94037564736f6c634300080f00330000000000000000000000002286d7f9639e8158fad1169e76d1fbc38247f54b00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675
Deployed Bytecode
0x6080604052600436106101515760003560e01c80621d35671461015657806302b1d2391461017857806307e0db17146101ae57806310ddb137146101ce5780631b2083dc146101ee57806322f3e2d4146102235780632556e453146102485780633d8b38f61461025b57806342d65a8d1461027b5780634657b36c1461029b578063577de7d0146102bb5780635924be70146102db5780635b8c41e6146102fd5780636edb3d3c1461035a5780637533d7881461037a578063923cb952146103a75780639459b875146103c7578063950c8a74146103e95780639f38369a14610409578063a6c3d16514610429578063b353aaa714610449578063baf3292d1461047d578063cbed8b9c1461049d578063d1deba1f146104bd578063d4aae0c4146104d0578063d58a8483146104f0578063ead93c8f14610510578063eb8d72b714610531578063f5ecbdbc14610551575b600080fd5b34801561016257600080fd5b50610176610171366004611f38565b610571565b005b34801561018457600080fd5b50600354610198906001600160a01b031681565b6040516101a59190611fcb565b60405180910390f35b3480156101ba57600080fd5b506101766101c9366004611fdf565b61081a565b3480156101da57600080fd5b506101766101e9366004611fdf565b61090f565b3480156101fa57600080fd5b5061020e610209366004612012565b6109d2565b604080519283526020830191909152016101a5565b34801561022f57600080fd5b50610238610aa0565b60405190151581526020016101a5565b610176610256366004612082565b610b17565b34801561026757600080fd5b506102386102763660046120c1565b610cb8565b34801561028757600080fd5b506101766102963660046120c1565b610dbd565b3480156102a757600080fd5b506101766102b6366004612113565b610eb8565b3480156102c757600080fd5b50600254610198906001600160a01b031681565b3480156102e757600080fd5b506102f0610f10565b6040516101a59190612130565b34801561030957600080fd5b5061034c610318366004612256565b6004602090815260009384526040808520845180860184018051928152908401958401959095209452929052825290205481565b6040519081526020016101a5565b34801561036657600080fd5b506101766103753660046122b3565b6110af565b34801561038657600080fd5b5061039a610395366004611fdf565b6110e1565b6040516101a5919061238f565b3480156103b357600080fd5b50600154610198906001600160a01b031681565b3480156103d357600080fd5b506103dc61117b565b6040516101a591906123a2565b3480156103f557600080fd5b50600654610198906001600160a01b031681565b34801561041557600080fd5b5061039a610424366004611fdf565b611318565b34801561043557600080fd5b506101766104443660046120c1565b6113ff565b34801561045557600080fd5b506101987f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd67581565b34801561048957600080fd5b50610176610498366004612113565b6114f4565b3480156104a957600080fd5b506101766104b83660046123f0565b6115be565b6101766104cb366004611f38565b6116bf565b3480156104dc57600080fd5b50600054610198906001600160a01b031681565b3480156104fc57600080fd5b5061017661050b36600461242d565b611861565b34801561051c57600080fd5b5060035461023890600160a01b900460ff1681565b34801561053d57600080fd5b5061017661054c3660046120c1565b611921565b34801561055d57600080fd5b5061039a61056c36600461244a565b6119e6565b336001600160a01b037f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd67516146105ba576040516395946b5d60e01b815260040160405180910390fd5b61ffff8616600090815260056020526040812080546105d890612497565b80601f016020809104026020016040519081016040528092919081815260200182805461060490612497565b80156106515780601f1061062657610100808354040283529160200191610651565b820191906000526020600020905b81548152906001019060200180831161063457829003601f168201915b50505050509050805160001480610669575080518514155b8061069157508051602082012060405161068690889088906124d1565b604051809103902014155b156106af57604051634488ea9760e11b815260040160405180910390fd5b600080306001600160a01b0316636edb3d3c60e01b8a8a8a8a8a8a6040516024016106df9695949392919061250a565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161071d9190612557565b6000604051808303816000865af19150503d806000811461075a576040519150601f19603f3d011682016040523d82523d6000602084013e61075f565b606091505b50915091508161080f5784846040516107799291906124d1565b6040805191829003822061ffff8c16600090815260046020529190912090916107a5908b908b906124d1565b9081526040805191829003602090810183206001600160401b038b166000908152915220919091557fe183f33de2837795525b4792ca4cd60535bd77c53b7e7030060bfcf5734d6b0c90610806908b908b908b908b908b908b908990612573565b60405180910390a15b505050505050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061085b90849033906004016125d5565b600060405180830381600087803b15801561087557600080fd5b505af1158015610889573d6000803e3d6000fd5b50506040516307e0db1760e01b815261ffff851660048201527f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd6756001600160a01b031692506307e0db1791506024015b600060405180830381600087803b1580156108f357600080fd5b505af1158015610907573d6000803e3d6000fd5b505050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061095090849033906004016125d5565b600060405180830381600087803b15801561096a57600080fd5b505af115801561097e573d6000803e3d6000fd5b50506040516310ddb13760e01b815261ffff851660048201527f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd6756001600160a01b031692506310ddb13791506024016108d9565b600080600086866040516020016109ea9291906125ec565b60408051601f198184030181529082905263040a7bb160e41b825291506001600160a01b037f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd67516906340a7bb1090610a51908b90309086906000908c908c90600401612605565b6040805180830381865afa158015610a6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a91919061264e565b92509250509550959350505050565b6000805460405163e52223bb60e01b81526001600160a01b039091169063e52223bb90610ad1903090600401611fcb565b602060405180830381865afa158015610aee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b129190612672565b905090565b600354600160a01b900460ff16610b4157604051638bfcdf0d60e01b815260040160405180910390fd5b6003546040516370a0823160e01b815282916001600160a01b0316906370a0823190610b71903390600401611fcb565b602060405180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb2919061268f565b1015610bd15760405163ea7aa0c560e01b815260040160405180910390fd5b60008282604051602001610be69291906125ec565b60408051601f198184030181529082905260025463557856ad60e11b83529092506001600160a01b03169063aaf0ad5a90610c2790339086906004016125ec565b600060405180830381600087803b158015610c4157600080fd5b505af1158015610c55573d6000803e3d6000fd5b50505050610c7784823360006040518060200160405280600081525034611a8e565b60405182815261ffff85169033907f39a9310c2653c9e8416b19cc7ef7166640ed10fa3a958f2804c1b3d75f2081019060200160405180910390a350505050565b61ffff831660009081526005602052604081208054829190610cd990612497565b80601f0160208091040260200160405190810160405280929190818152602001828054610d0590612497565b8015610d525780601f10610d2757610100808354040283529160200191610d52565b820191906000526020600020905b815481529060010190602001808311610d3557829003601f168201915b505050505090508383905060001480610d6a57508051155b15610d88576040516302c18f6d60e31b815260040160405180910390fd5b805183148015610db4575080516020820120604051610daa90869086906124d1565b6040518091039020145b95945050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c590610dfe90849033906004016125d5565b600060405180830381600087803b158015610e1857600080fd5b505af1158015610e2c573d6000803e3d6000fd5b50506040516342d65a8d60e01b81526001600160a01b037f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd6751692506342d65a8d9150610e80908790879087906004016126a8565b600060405180830381600087803b158015610e9a57600080fd5b505af1158015610eae573d6000803e3d6000fd5b5050505050505050565b6000546001600160a01b03163314610eee573360405163053e900f60e21b8152600401610ee59190611fcb565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b60606000600260009054906101000a90046001600160a01b03166001600160a01b0316631ae7ec2e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8b91906126c6565b60408051600380825260808201909252919250816020015b6040805180820190915260008082526020820152815260200190600190039081610fa3575050604080518082019091526001600160d81b031983168152633a56e30760e01b60208201528151919350908390600090611004576110046126f0565b60200260200101819052506040518060400160405280826001600160d81b031916815260200163aaf0ad5a60e01b6001600160e01b03191681525082600181518110611052576110526126f0565b60200260200101819052506040518060400160405280826001600160d81b031916815260200163359fe78060e01b6001600160e01b031916815250826002815181106110a0576110a06126f0565b60200260200101819052505090565b3330146110cf576040516395946b5d60e01b815260040160405180910390fd5b6110db84848484611be0565b50505050565b600560205260009081526040902080546110fa90612497565b80601f016020809104026020016040519081016040528092919081815260200182805461112690612497565b80156111735780601f1061114857610100808354040283529160200191611173565b820191906000526020600020905b81548152906001019060200180831161115657829003601f168201915b505050505081565b60408051600280825260608083018452926020830190803683370190505090506426a4a72a2960d91b816000815181106111b7576111b76126f0565b6001600160d81b0319909216602092830291909101909101526111df64524f4c455360d81b90565b816001815181106111f2576111f26126f0565b60200260200101906001600160d81b03191690816001600160d81b031916815250506112378160008151811061122a5761122a6126f0565b6020026020010151611d12565b600260006101000a8154816001600160a01b0302191690836001600160a01b031602179055506112738160018151811061122a5761122a6126f0565b600180546001600160a01b0319166001600160a01b03928316179055600254604080516302b1d23960e01b8152905191909216916302b1d2399160048083019260209291908290030181865afa1580156112d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f59190612706565b600380546001600160a01b0319166001600160a01b039290921691909117905590565b61ffff811660009081526005602052604081208054606092919061133b90612497565b80601f016020809104026020016040519081016040528092919081815260200182805461136790612497565b80156113b45780601f10611389576101008083540402835291602001916113b4565b820191906000526020600020905b81548152906001019060200180831161139757829003601f168201915b5050505050905080516000036113dd576040516302fa5b7760e41b815260040160405180910390fd5b6113f86000601483516113f09190612739565b839190611db5565b9392505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061144090849033906004016125d5565b600060405180830381600087803b15801561145a57600080fd5b505af115801561146e573d6000803e3d6000fd5b5050505082823060405160200161148793929190612750565b60408051601f1981840301815291815261ffff86166000908152600560205220906114b290826127d1565b507f8c0400cfe2d1199b1a725c78960bcc2a344d869b80590d0f2bd005db15a572ce8484846040516114e6939291906126a8565b60405180910390a150505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061153590849033906004016125d5565b600060405180830381600087803b15801561154f57600080fd5b505af1158015611563573d6000803e3d6000fd5b5050600680546001600160a01b0319166001600160a01b03861617905550506040517f5db758e995a17ec1ad84bdef7e8c3293a0bd6179bcce400dff5d4c3d87db726b906115b2908490611fcb565b60405180910390a15050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c5906115ff90849033906004016125d5565b600060405180830381600087803b15801561161957600080fd5b505af115801561162d573d6000803e3d6000fd5b50506040516332fb62e760e21b81526001600160a01b037f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd67516925063cbed8b9c9150611685908990899089908990899060040161288a565b600060405180830381600087803b15801561169f57600080fd5b505af11580156116b3573d6000803e3d6000fd5b50505050505050505050565b61ffff861660009081526004602052604080822090516116e290889088906124d1565b90815260408051602092819003830190206001600160401b038716600090815292529020549050806117275760405163033f21d760e31b815260040160405180910390fd5b8083836040516117389291906124d1565b60405180910390201461175e57604051633d161b8760e11b815260040160405180910390fd5b61ffff8716600090815260046020526040808220905161178190899089906124d1565b90815260408051602092819003830181206001600160401b038916600090815290845282902093909355601f88018290048202830182019052868252611819918991899089908190840183828082843760009201919091525050604080516020601f8a018190048102820181019092528881528a935091508890889081908401838280828437600092019190915250611be092505050565b7fc264d91f3adc5588250e1551f547752ca0cfa8f6b530d243b9f9f4cab10ea8e587878787856040516118509594939291906128c3565b60405180910390a150505050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c5906118a290849033906004016125d5565b600060405180830381600087803b1580156118bc57600080fd5b505af11580156118d0573d6000803e3d6000fd5b505060038054851515600160a01b0260ff60a01b1990911617905550506040517f0c8765b60c3fca0b25c8c97ac199bdf1a16d429abbe4213d48ba4a66d666f241906115b290841515815260200190565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061196290849033906004016125d5565b600060405180830381600087803b15801561197c57600080fd5b505af1158015611990573d6000803e3d6000fd5b5050505061ffff841660009081526005602052604090206119b28385836128fe565b507ffa41487ad5d6728f0b19276fa1eddc16558578f5109fc39d2dc33c3230470dab8484846040516114e6939291906126a8565b604051633d7b2f6f60e21b815261ffff808616600483015284166024820152306044820152606481018290526060907f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd6756001600160a01b03169063f5ecbdbc90608401600060405180830381865afa158015611a66573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610db491908101906129b8565b61ffff861660009081526005602052604081208054611aac90612497565b80601f0160208091040260200160405190810160405280929190818152602001828054611ad890612497565b8015611b255780601f10611afa57610100808354040283529160200191611b25565b820191906000526020600020905b815481529060010190602001808311611b0857829003601f168201915b505050505090508051600003611b4e576040516303e334ff60e51b815260040160405180910390fd5b60405162c5803160e81b81526001600160a01b037f00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675169063c5803100908490611ba5908b9086908c908c908c908c90600401612a25565b6000604051808303818588803b158015611bbe57600080fd5b505af1158015611bd2573d6000803e3d6000fd5b505050505050505050505050565b60008082806020019051810190611bf79190612a7f565b600254604051626b3fcf60e71b81529294509092506001600160a01b03169063359fe78090611c2c90309085906004016125ec565b600060405180830381600087803b158015611c4657600080fd5b505af1158015611c5a573d6000803e3d6000fd5b5050600254604051633a56e30760e01b81526001600160a01b039091169250633a56e3079150611c9090859085906004016125ec565b600060405180830381600087803b158015611caa57600080fd5b505af1158015611cbe573d6000803e3d6000fd5b505050508561ffff16826001600160a01b03167f66e72df5c00d93ba421714963fffa44e34b0f51ad224cd6966565fc089be93f883604051611d0291815260200190565b60405180910390a3505050505050565b60008054604051632d37002d60e21b815282916001600160a01b03169063b4dc00b490611d43908690600401612aad565b602060405180830381865afa158015611d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d849190612706565b90506001600160a01b038116611daf5782604051635c3fa9cd60e01b8152600401610ee59190612aad565b92915050565b606081611dc381601f612ac2565b1015611e025760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610ee5565b611e0c8284612ac2565b84511015611e505760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610ee5565b606082158015611e6f5760405191506000825260208201604052611eb9565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015611ea8578051835260209283019201611e90565b5050858452601f01601f1916604052505b50949350505050565b803561ffff81168114611ed457600080fd5b919050565b60008083601f840112611eeb57600080fd5b5081356001600160401b03811115611f0257600080fd5b602083019150836020828501011115611f1a57600080fd5b9250929050565b80356001600160401b0381168114611ed457600080fd5b60008060008060008060808789031215611f5157600080fd5b611f5a87611ec2565b955060208701356001600160401b0380821115611f7657600080fd5b611f828a838b01611ed9565b9097509550859150611f9660408a01611f21565b94506060890135915080821115611fac57600080fd5b50611fb989828a01611ed9565b979a9699509497509295939492505050565b6001600160a01b0391909116815260200190565b600060208284031215611ff157600080fd5b6113f882611ec2565b6001600160a01b038116811461200f57600080fd5b50565b60008060008060006080868803121561202a57600080fd5b61203386611ec2565b9450602086013561204381611ffa565b93506040860135925060608601356001600160401b0381111561206557600080fd5b61207188828901611ed9565b969995985093965092949392505050565b60008060006060848603121561209757600080fd5b6120a084611ec2565b925060208401356120b081611ffa565b929592945050506040919091013590565b6000806000604084860312156120d657600080fd5b6120df84611ec2565b925060208401356001600160401b038111156120fa57600080fd5b61210686828701611ed9565b9497909650939450505050565b60006020828403121561212557600080fd5b81356113f881611ffa565b602080825282518282018190526000919060409081850190868401855b8281101561218657815180516001600160d81b03191685528601516001600160e01b03191686850152928401929085019060010161214d565b5091979650505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156121d1576121d1612193565b604052919050565b60006001600160401b038211156121f2576121f2612193565b50601f01601f191660200190565b600082601f83011261221157600080fd5b813561222461221f826121d9565b6121a9565b81815284602083860101111561223957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561226b57600080fd5b61227484611ec2565b925060208401356001600160401b0381111561228f57600080fd5b61229b86828701612200565b9250506122aa60408501611f21565b90509250925092565b600080600080608085870312156122c957600080fd5b6122d285611ec2565b935060208501356001600160401b03808211156122ee57600080fd5b6122fa88838901612200565b945061230860408801611f21565b9350606087013591508082111561231e57600080fd5b5061232b87828801612200565b91505092959194509250565b60005b8381101561235257818101518382015260200161233a565b838111156110db5750506000910152565b6000815180845261237b816020860160208601612337565b601f01601f19169290920160200192915050565b6020815260006113f86020830184612363565b6020808252825182820181905260009190848201906040850190845b818110156123e45783516001600160d81b031916835292840192918401916001016123be565b50909695505050505050565b60008060008060006080868803121561240857600080fd5b61241186611ec2565b945061204360208701611ec2565b801515811461200f57600080fd5b60006020828403121561243f57600080fd5b81356113f88161241f565b6000806000806080858703121561246057600080fd5b61246985611ec2565b935061247760208601611ec2565b9250604085013561248781611ffa565b9396929550929360600135925050565b600181811c908216806124ab57607f821691505b6020821081036124cb57634e487b7160e01b600052602260045260246000fd5b50919050565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b61ffff871681526080602082015260006125286080830187896124e1565b6001600160401b0386166040840152828103606084015261254a8185876124e1565b9998505050505050505050565b60008251612569818460208701612337565b9190910192915050565b61ffff8816815260a06020820152600061259160a08301888a6124e1565b6001600160401b038716604084015282810360608401526125b38186886124e1565b905082810360808401526125c78185612363565b9a9950505050505050505050565b9182526001600160a01b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b61ffff871681526001600160a01b038616602082015260a06040820181905260009061263390830187612363565b8515156060840152828103608084015261254a8185876124e1565b6000806040838503121561266157600080fd5b505080516020909101519092909150565b60006020828403121561268457600080fd5b81516113f88161241f565b6000602082840312156126a157600080fd5b5051919050565b61ffff84168152604060208201526000610db46040830184866124e1565b6000602082840312156126d857600080fd5b81516001600160d81b0319811681146113f857600080fd5b634e487b7160e01b600052603260045260246000fd5b60006020828403121561271857600080fd5b81516113f881611ffa565b634e487b7160e01b600052601160045260246000fd5b60008282101561274b5761274b612723565b500390565b8284823760609190911b6001600160601b0319169101908152601401919050565b601f8211156127b757600081815260208120601f850160051c810160208610156127985750805b601f850160051c820191505b81811015610907578281556001016127a4565b505050565b600019600383901b1c191660019190911b1790565b81516001600160401b038111156127ea576127ea612193565b6127fe816127f88454612497565b84612771565b602080601f83116001811461282d576000841561281b5750858301515b61282585826127bc565b865550610907565b600085815260208120601f198616915b8281101561285c5788860151825594840194600190910190840161283d565b508582101561287a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600061ffff8088168352808716602084015250846040830152608060608301526128b86080830184866124e1565b979650505050505050565b61ffff861681526080602082015260006128e16080830186886124e1565b6001600160401b0394909416604083015250606001529392505050565b6001600160401b0383111561291557612915612193565b612929836129238354612497565b83612771565b6000601f84116001811461295757600085156129455750838201355b61294f86826127bc565b8455506129b1565b600083815260209020601f19861690835b828110156129885786850135825560209485019460019092019101612968565b50868210156129a55760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6000602082840312156129ca57600080fd5b81516001600160401b038111156129e057600080fd5b8201601f810184136129f157600080fd5b80516129ff61221f826121d9565b818152856020838501011115612a1457600080fd5b610db4826020830160208601612337565b61ffff8716815260c060208201526000612a4260c0830188612363565b8281036040840152612a548188612363565b6001600160a01b0387811660608601528616608085015283810360a0850152905061254a8185612363565b60008060408385031215612a9257600080fd5b8251612a9d81611ffa565b6020939093015192949293505050565b6001600160d81b031991909116815260200190565b60008219821115612ad557612ad5612723565b50019056fea26469706673582212209f66fcbf215ccd5b466f7bbca94fb27deb3a9915741e80454e6d04704b94037564736f6c634300080f0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002286d7f9639e8158fad1169e76d1fbc38247f54b00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675
-----Decoded View---------------
Arg [0] : kernel_ (address): 0x2286d7f9639e8158FaD1169e76d1FbC38247f54b
Arg [1] : endpoint_ (address): 0x66A71Dcef29A0fFBDBE3c6a460a3B5BC225Cd675
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000002286d7f9639e8158fad1169e76d1fbc38247f54b
Arg [1] : 00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ 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.