Latest 25 from a total of 2,407 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Send Ohm | 425169265 | 9 hrs ago | IN | 0.00007783 ETH | 0.00000529 | ||||
| Send Ohm | 423749263 | 4 days ago | IN | 0.00004782 ETH | 0.0000052 | ||||
| Send Ohm | 423487303 | 5 days ago | IN | 0.00004272 ETH | 0.00001458 | ||||
| Send Ohm | 422821169 | 7 days ago | IN | 0.0000635 ETH | 0.00000605 | ||||
| Send Ohm | 422816622 | 7 days ago | IN | 0.00004521 ETH | 0.00001713 | ||||
| Send Ohm | 421662781 | 10 days ago | IN | 0.00004714 ETH | 0.00000497 | ||||
| Send Ohm | 420605670 | 13 days ago | IN | 0.00082464 ETH | 0.00000517 | ||||
| Send Ohm | 415734428 | 27 days ago | IN | 0.00088243 ETH | 0.00000914 | ||||
| Send Ohm | 415730309 | 27 days ago | IN | 0.00083715 ETH | 0.00000787 | ||||
| Send Ohm | 415694866 | 27 days ago | IN | 0.00086663 ETH | 0.0000078 | ||||
| Send Ohm | 415521197 | 28 days ago | IN | 0.00081825 ETH | 0.00000251 | ||||
| Send Ohm | 415514232 | 28 days ago | IN | 0.00082041 ETH | 0.00000251 | ||||
| Send Ohm | 415422402 | 28 days ago | IN | 0.000747 ETH | 0.00000235 | ||||
| Send Ohm | 414915600 | 30 days ago | IN | 0.0007458 ETH | 0.0000024 | ||||
| Send Ohm | 414913326 | 30 days ago | IN | 0.000044 ETH | 0.0000024 | ||||
| Send Ohm | 414840003 | 30 days ago | IN | 0.000044 ETH | 0.0000005 | ||||
| Send Ohm | 414733366 | 30 days ago | IN | 0.00004547 ETH | 0.00001849 | ||||
| Send Ohm | 414082643 | 32 days ago | IN | 0.0007496 ETH | 0.00001686 | ||||
| Send Ohm | 413695239 | 33 days ago | IN | 0.00084432 ETH | 0.00001429 | ||||
| Send Ohm | 413429381 | 34 days ago | IN | 0.00082145 ETH | 0.00000414 | ||||
| Send Ohm | 412945828 | 35 days ago | IN | 0.00004433 ETH | 0.00000235 | ||||
| Send Ohm | 412053959 | 38 days ago | IN | 0.00087046 ETH | 0.00000251 | ||||
| Send Ohm | 412023968 | 38 days ago | IN | 0.00087454 ETH | 0.00000323 | ||||
| Send Ohm | 412000043 | 38 days ago | IN | 0.00090019 ETH | 0.00006028 | ||||
| Send Ohm | 411998727 | 38 days ago | IN | 0.00004873 ETH | 0.00004547 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 425183172 | 8 hrs ago | 0.00005168 ETH | ||||
| 425183172 | 8 hrs ago | 0.00005168 ETH | ||||
| 425176158 | 8 hrs ago | 0.0001243 ETH | ||||
| 425176158 | 8 hrs ago | 0.0001243 ETH | ||||
| 425169265 | 9 hrs ago | 0.00007783 ETH | ||||
| 425169159 | 9 hrs ago | 0.00006549 ETH | ||||
| 425169159 | 9 hrs ago | 0.00006549 ETH | ||||
| 425167940 | 9 hrs ago | 0.00004927 ETH | ||||
| 425167940 | 9 hrs ago | 0.00004927 ETH | ||||
| 425157112 | 10 hrs ago | 0.00007394 ETH | ||||
| 425157112 | 10 hrs ago | 0.00007394 ETH | ||||
| 425154976 | 10 hrs ago | 0.0000512 ETH | ||||
| 425154976 | 10 hrs ago | 0.0000512 ETH | ||||
| 425152799 | 10 hrs ago | 0.00004811 ETH | ||||
| 425152799 | 10 hrs ago | 0.00004811 ETH | ||||
| 425124917 | 12 hrs ago | 0.00005395 ETH | ||||
| 425124917 | 12 hrs ago | 0.00005395 ETH | ||||
| 425121292 | 12 hrs ago | 0.00005183 ETH | ||||
| 425121292 | 12 hrs ago | 0.00005183 ETH | ||||
| 424410696 | 2 days ago | 0.00005002 ETH | ||||
| 424410696 | 2 days ago | 0.00005002 ETH | ||||
| 424076263 | 3 days ago | 0.00004753 ETH | ||||
| 424076263 | 3 days ago | 0.00004753 ETH | ||||
| 424076033 | 3 days ago | 0.00004753 ETH | ||||
| 424076033 | 3 days ago | 0.00004753 ETH |
Cross-Chain Transactions
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
Contract ABI
API[{"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
60a06040523480156200001157600080fd5b5060405162002c2b38038062002c2b833981016040819052620000349162000088565b600080546001600160a01b039384166001600160a01b0319909116179055166080526003805460ff60a01b1916600160a01b179055620000c7565b6001600160a01b03811681146200008557600080fd5b50565b600080604083850312156200009c57600080fd5b8251620000a9816200006f565b6020840151909250620000bc816200006f565b809150509250929050565b608051612b106200011b6000396000818161045b0152818161057c015281816108a40152818161099901528181610a1101528181610e450152818161164601528181611a170152611b640152612b106000f3fe6080604052600436106101515760003560e01c80621d35671461015657806302b1d2391461017857806307e0db17146101ae57806310ddb137146101ce5780631b2083dc146101ee57806322f3e2d4146102235780632556e453146102485780633d8b38f61461025b57806342d65a8d1461027b5780634657b36c1461029b578063577de7d0146102bb5780635924be70146102db5780635b8c41e6146102fd5780636edb3d3c1461035a5780637533d7881461037a578063923cb952146103a75780639459b875146103c7578063950c8a74146103e95780639f38369a14610409578063a6c3d16514610429578063b353aaa714610449578063baf3292d1461047d578063cbed8b9c1461049d578063d1deba1f146104bd578063d4aae0c4146104d0578063d58a8483146104f0578063ead93c8f14610510578063eb8d72b714610531578063f5ecbdbc14610551575b600080fd5b34801561016257600080fd5b50610176610171366004611f38565b610571565b005b34801561018457600080fd5b50600354610198906001600160a01b031681565b6040516101a59190611fcb565b60405180910390f35b3480156101ba57600080fd5b506101766101c9366004611fdf565b61081a565b3480156101da57600080fd5b506101766101e9366004611fdf565b61090f565b3480156101fa57600080fd5b5061020e610209366004612012565b6109d2565b604080519283526020830191909152016101a5565b34801561022f57600080fd5b50610238610aa0565b60405190151581526020016101a5565b610176610256366004612082565b610b17565b34801561026757600080fd5b506102386102763660046120c1565b610cb8565b34801561028757600080fd5b506101766102963660046120c1565b610dbd565b3480156102a757600080fd5b506101766102b6366004612113565b610eb8565b3480156102c757600080fd5b50600254610198906001600160a01b031681565b3480156102e757600080fd5b506102f0610f10565b6040516101a59190612130565b34801561030957600080fd5b5061034c610318366004612256565b6004602090815260009384526040808520845180860184018051928152908401958401959095209452929052825290205481565b6040519081526020016101a5565b34801561036657600080fd5b506101766103753660046122b3565b6110af565b34801561038657600080fd5b5061039a610395366004611fdf565b6110e1565b6040516101a5919061238f565b3480156103b357600080fd5b50600154610198906001600160a01b031681565b3480156103d357600080fd5b506103dc61117b565b6040516101a591906123a2565b3480156103f557600080fd5b50600654610198906001600160a01b031681565b34801561041557600080fd5b5061039a610424366004611fdf565b611318565b34801561043557600080fd5b506101766104443660046120c1565b6113ff565b34801561045557600080fd5b506101987f000000000000000000000000000000000000000000000000000000000000000081565b34801561048957600080fd5b50610176610498366004612113565b6114f4565b3480156104a957600080fd5b506101766104b83660046123f0565b6115be565b6101766104cb366004611f38565b6116bf565b3480156104dc57600080fd5b50600054610198906001600160a01b031681565b3480156104fc57600080fd5b5061017661050b36600461242d565b611861565b34801561051c57600080fd5b5060035461023890600160a01b900460ff1681565b34801561053d57600080fd5b5061017661054c3660046120c1565b611921565b34801561055d57600080fd5b5061039a61056c36600461244a565b6119e6565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146105ba576040516395946b5d60e01b815260040160405180910390fd5b61ffff8616600090815260056020526040812080546105d890612497565b80601f016020809104026020016040519081016040528092919081815260200182805461060490612497565b80156106515780601f1061062657610100808354040283529160200191610651565b820191906000526020600020905b81548152906001019060200180831161063457829003601f168201915b50505050509050805160001480610669575080518514155b8061069157508051602082012060405161068690889088906124d1565b604051809103902014155b156106af57604051634488ea9760e11b815260040160405180910390fd5b600080306001600160a01b0316636edb3d3c60e01b8a8a8a8a8a8a6040516024016106df9695949392919061250a565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161071d9190612557565b6000604051808303816000865af19150503d806000811461075a576040519150601f19603f3d011682016040523d82523d6000602084013e61075f565b606091505b50915091508161080f5784846040516107799291906124d1565b6040805191829003822061ffff8c16600090815260046020529190912090916107a5908b908b906124d1565b9081526040805191829003602090810183206001600160401b038b166000908152915220919091557fe183f33de2837795525b4792ca4cd60535bd77c53b7e7030060bfcf5734d6b0c90610806908b908b908b908b908b908b908990612573565b60405180910390a15b505050505050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061085b90849033906004016125d5565b600060405180830381600087803b15801561087557600080fd5b505af1158015610889573d6000803e3d6000fd5b50506040516307e0db1760e01b815261ffff851660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692506307e0db1791506024015b600060405180830381600087803b1580156108f357600080fd5b505af1158015610907573d6000803e3d6000fd5b505050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061095090849033906004016125d5565b600060405180830381600087803b15801561096a57600080fd5b505af115801561097e573d6000803e3d6000fd5b50506040516310ddb13760e01b815261ffff851660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692506310ddb13791506024016108d9565b600080600086866040516020016109ea9291906125ec565b60408051601f198184030181529082905263040a7bb160e41b825291506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906340a7bb1090610a51908b90309086906000908c908c90600401612605565b6040805180830381865afa158015610a6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a91919061264e565b92509250509550959350505050565b6000805460405163e52223bb60e01b81526001600160a01b039091169063e52223bb90610ad1903090600401611fcb565b602060405180830381865afa158015610aee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b129190612672565b905090565b600354600160a01b900460ff16610b4157604051638bfcdf0d60e01b815260040160405180910390fd5b6003546040516370a0823160e01b815282916001600160a01b0316906370a0823190610b71903390600401611fcb565b602060405180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb2919061268f565b1015610bd15760405163ea7aa0c560e01b815260040160405180910390fd5b60008282604051602001610be69291906125ec565b60408051601f198184030181529082905260025463557856ad60e11b83529092506001600160a01b03169063aaf0ad5a90610c2790339086906004016125ec565b600060405180830381600087803b158015610c4157600080fd5b505af1158015610c55573d6000803e3d6000fd5b50505050610c7784823360006040518060200160405280600081525034611a8e565b60405182815261ffff85169033907f39a9310c2653c9e8416b19cc7ef7166640ed10fa3a958f2804c1b3d75f2081019060200160405180910390a350505050565b61ffff831660009081526005602052604081208054829190610cd990612497565b80601f0160208091040260200160405190810160405280929190818152602001828054610d0590612497565b8015610d525780601f10610d2757610100808354040283529160200191610d52565b820191906000526020600020905b815481529060010190602001808311610d3557829003601f168201915b505050505090508383905060001480610d6a57508051155b15610d88576040516302c18f6d60e31b815260040160405180910390fd5b805183148015610db4575080516020820120604051610daa90869086906124d1565b6040518091039020145b95945050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c590610dfe90849033906004016125d5565b600060405180830381600087803b158015610e1857600080fd5b505af1158015610e2c573d6000803e3d6000fd5b50506040516342d65a8d60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692506342d65a8d9150610e80908790879087906004016126a8565b600060405180830381600087803b158015610e9a57600080fd5b505af1158015610eae573d6000803e3d6000fd5b5050505050505050565b6000546001600160a01b03163314610eee573360405163053e900f60e21b8152600401610ee59190611fcb565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b60606000600260009054906101000a90046001600160a01b03166001600160a01b0316631ae7ec2e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8b91906126c6565b60408051600380825260808201909252919250816020015b6040805180820190915260008082526020820152815260200190600190039081610fa3575050604080518082019091526001600160d81b031983168152633a56e30760e01b60208201528151919350908390600090611004576110046126f0565b60200260200101819052506040518060400160405280826001600160d81b031916815260200163aaf0ad5a60e01b6001600160e01b03191681525082600181518110611052576110526126f0565b60200260200101819052506040518060400160405280826001600160d81b031916815260200163359fe78060e01b6001600160e01b031916815250826002815181106110a0576110a06126f0565b60200260200101819052505090565b3330146110cf576040516395946b5d60e01b815260040160405180910390fd5b6110db84848484611be0565b50505050565b600560205260009081526040902080546110fa90612497565b80601f016020809104026020016040519081016040528092919081815260200182805461112690612497565b80156111735780601f1061114857610100808354040283529160200191611173565b820191906000526020600020905b81548152906001019060200180831161115657829003601f168201915b505050505081565b60408051600280825260608083018452926020830190803683370190505090506426a4a72a2960d91b816000815181106111b7576111b76126f0565b6001600160d81b0319909216602092830291909101909101526111df64524f4c455360d81b90565b816001815181106111f2576111f26126f0565b60200260200101906001600160d81b03191690816001600160d81b031916815250506112378160008151811061122a5761122a6126f0565b6020026020010151611d12565b600260006101000a8154816001600160a01b0302191690836001600160a01b031602179055506112738160018151811061122a5761122a6126f0565b600180546001600160a01b0319166001600160a01b03928316179055600254604080516302b1d23960e01b8152905191909216916302b1d2399160048083019260209291908290030181865afa1580156112d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f59190612706565b600380546001600160a01b0319166001600160a01b039290921691909117905590565b61ffff811660009081526005602052604081208054606092919061133b90612497565b80601f016020809104026020016040519081016040528092919081815260200182805461136790612497565b80156113b45780601f10611389576101008083540402835291602001916113b4565b820191906000526020600020905b81548152906001019060200180831161139757829003601f168201915b5050505050905080516000036113dd576040516302fa5b7760e41b815260040160405180910390fd5b6113f86000601483516113f09190612739565b839190611db5565b9392505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061144090849033906004016125d5565b600060405180830381600087803b15801561145a57600080fd5b505af115801561146e573d6000803e3d6000fd5b5050505082823060405160200161148793929190612750565b60408051601f1981840301815291815261ffff86166000908152600560205220906114b290826127d1565b507f8c0400cfe2d1199b1a725c78960bcc2a344d869b80590d0f2bd005db15a572ce8484846040516114e6939291906126a8565b60405180910390a150505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061153590849033906004016125d5565b600060405180830381600087803b15801561154f57600080fd5b505af1158015611563573d6000803e3d6000fd5b5050600680546001600160a01b0319166001600160a01b03861617905550506040517f5db758e995a17ec1ad84bdef7e8c3293a0bd6179bcce400dff5d4c3d87db726b906115b2908490611fcb565b60405180910390a15050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c5906115ff90849033906004016125d5565b600060405180830381600087803b15801561161957600080fd5b505af115801561162d573d6000803e3d6000fd5b50506040516332fb62e760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063cbed8b9c9150611685908990899089908990899060040161288a565b600060405180830381600087803b15801561169f57600080fd5b505af11580156116b3573d6000803e3d6000fd5b50505050505050505050565b61ffff861660009081526004602052604080822090516116e290889088906124d1565b90815260408051602092819003830190206001600160401b038716600090815292529020549050806117275760405163033f21d760e31b815260040160405180910390fd5b8083836040516117389291906124d1565b60405180910390201461175e57604051633d161b8760e11b815260040160405180910390fd5b61ffff8716600090815260046020526040808220905161178190899089906124d1565b90815260408051602092819003830181206001600160401b038916600090815290845282902093909355601f88018290048202830182019052868252611819918991899089908190840183828082843760009201919091525050604080516020601f8a018190048102820181019092528881528a935091508890889081908401838280828437600092019190915250611be092505050565b7fc264d91f3adc5588250e1551f547752ca0cfa8f6b530d243b9f9f4cab10ea8e587878787856040516118509594939291906128c3565b60405180910390a150505050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c5906118a290849033906004016125d5565b600060405180830381600087803b1580156118bc57600080fd5b505af11580156118d0573d6000803e3d6000fd5b505060038054851515600160a01b0260ff60a01b1990911617905550506040517f0c8765b60c3fca0b25c8c97ac199bdf1a16d429abbe4213d48ba4a66d666f241906115b290841515815260200190565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061196290849033906004016125d5565b600060405180830381600087803b15801561197c57600080fd5b505af1158015611990573d6000803e3d6000fd5b5050505061ffff841660009081526005602052604090206119b28385836128fe565b507ffa41487ad5d6728f0b19276fa1eddc16558578f5109fc39d2dc33c3230470dab8484846040516114e6939291906126a8565b604051633d7b2f6f60e21b815261ffff808616600483015284166024820152306044820152606481018290526060907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f5ecbdbc90608401600060405180830381865afa158015611a66573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610db491908101906129b8565b61ffff861660009081526005602052604081208054611aac90612497565b80601f0160208091040260200160405190810160405280929190818152602001828054611ad890612497565b8015611b255780601f10611afa57610100808354040283529160200191611b25565b820191906000526020600020905b815481529060010190602001808311611b0857829003601f168201915b505050505090508051600003611b4e576040516303e334ff60e51b815260040160405180910390fd5b60405162c5803160e81b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c5803100908490611ba5908b9086908c908c908c908c90600401612a25565b6000604051808303818588803b158015611bbe57600080fd5b505af1158015611bd2573d6000803e3d6000fd5b505050505050505050505050565b60008082806020019051810190611bf79190612a7f565b600254604051626b3fcf60e71b81529294509092506001600160a01b03169063359fe78090611c2c90309085906004016125ec565b600060405180830381600087803b158015611c4657600080fd5b505af1158015611c5a573d6000803e3d6000fd5b5050600254604051633a56e30760e01b81526001600160a01b039091169250633a56e3079150611c9090859085906004016125ec565b600060405180830381600087803b158015611caa57600080fd5b505af1158015611cbe573d6000803e3d6000fd5b505050508561ffff16826001600160a01b03167f66e72df5c00d93ba421714963fffa44e34b0f51ad224cd6966565fc089be93f883604051611d0291815260200190565b60405180910390a3505050505050565b60008054604051632d37002d60e21b815282916001600160a01b03169063b4dc00b490611d43908690600401612aad565b602060405180830381865afa158015611d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d849190612706565b90506001600160a01b038116611daf5782604051635c3fa9cd60e01b8152600401610ee59190612aad565b92915050565b606081611dc381601f612ac2565b1015611e025760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610ee5565b611e0c8284612ac2565b84511015611e505760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610ee5565b606082158015611e6f5760405191506000825260208201604052611eb9565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015611ea8578051835260209283019201611e90565b5050858452601f01601f1916604052505b50949350505050565b803561ffff81168114611ed457600080fd5b919050565b60008083601f840112611eeb57600080fd5b5081356001600160401b03811115611f0257600080fd5b602083019150836020828501011115611f1a57600080fd5b9250929050565b80356001600160401b0381168114611ed457600080fd5b60008060008060008060808789031215611f5157600080fd5b611f5a87611ec2565b955060208701356001600160401b0380821115611f7657600080fd5b611f828a838b01611ed9565b9097509550859150611f9660408a01611f21565b94506060890135915080821115611fac57600080fd5b50611fb989828a01611ed9565b979a9699509497509295939492505050565b6001600160a01b0391909116815260200190565b600060208284031215611ff157600080fd5b6113f882611ec2565b6001600160a01b038116811461200f57600080fd5b50565b60008060008060006080868803121561202a57600080fd5b61203386611ec2565b9450602086013561204381611ffa565b93506040860135925060608601356001600160401b0381111561206557600080fd5b61207188828901611ed9565b969995985093965092949392505050565b60008060006060848603121561209757600080fd5b6120a084611ec2565b925060208401356120b081611ffa565b929592945050506040919091013590565b6000806000604084860312156120d657600080fd5b6120df84611ec2565b925060208401356001600160401b038111156120fa57600080fd5b61210686828701611ed9565b9497909650939450505050565b60006020828403121561212557600080fd5b81356113f881611ffa565b602080825282518282018190526000919060409081850190868401855b8281101561218657815180516001600160d81b03191685528601516001600160e01b03191686850152928401929085019060010161214d565b5091979650505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156121d1576121d1612193565b604052919050565b60006001600160401b038211156121f2576121f2612193565b50601f01601f191660200190565b600082601f83011261221157600080fd5b813561222461221f826121d9565b6121a9565b81815284602083860101111561223957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561226b57600080fd5b61227484611ec2565b925060208401356001600160401b0381111561228f57600080fd5b61229b86828701612200565b9250506122aa60408501611f21565b90509250925092565b600080600080608085870312156122c957600080fd5b6122d285611ec2565b935060208501356001600160401b03808211156122ee57600080fd5b6122fa88838901612200565b945061230860408801611f21565b9350606087013591508082111561231e57600080fd5b5061232b87828801612200565b91505092959194509250565b60005b8381101561235257818101518382015260200161233a565b838111156110db5750506000910152565b6000815180845261237b816020860160208601612337565b601f01601f19169290920160200192915050565b6020815260006113f86020830184612363565b6020808252825182820181905260009190848201906040850190845b818110156123e45783516001600160d81b031916835292840192918401916001016123be565b50909695505050505050565b60008060008060006080868803121561240857600080fd5b61241186611ec2565b945061204360208701611ec2565b801515811461200f57600080fd5b60006020828403121561243f57600080fd5b81356113f88161241f565b6000806000806080858703121561246057600080fd5b61246985611ec2565b935061247760208601611ec2565b9250604085013561248781611ffa565b9396929550929360600135925050565b600181811c908216806124ab57607f821691505b6020821081036124cb57634e487b7160e01b600052602260045260246000fd5b50919050565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b61ffff871681526080602082015260006125286080830187896124e1565b6001600160401b0386166040840152828103606084015261254a8185876124e1565b9998505050505050505050565b60008251612569818460208701612337565b9190910192915050565b61ffff8816815260a06020820152600061259160a08301888a6124e1565b6001600160401b038716604084015282810360608401526125b38186886124e1565b905082810360808401526125c78185612363565b9a9950505050505050505050565b9182526001600160a01b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b61ffff871681526001600160a01b038616602082015260a06040820181905260009061263390830187612363565b8515156060840152828103608084015261254a8185876124e1565b6000806040838503121561266157600080fd5b505080516020909101519092909150565b60006020828403121561268457600080fd5b81516113f88161241f565b6000602082840312156126a157600080fd5b5051919050565b61ffff84168152604060208201526000610db46040830184866124e1565b6000602082840312156126d857600080fd5b81516001600160d81b0319811681146113f857600080fd5b634e487b7160e01b600052603260045260246000fd5b60006020828403121561271857600080fd5b81516113f881611ffa565b634e487b7160e01b600052601160045260246000fd5b60008282101561274b5761274b612723565b500390565b8284823760609190911b6001600160601b0319169101908152601401919050565b601f8211156127b757600081815260208120601f850160051c810160208610156127985750805b601f850160051c820191505b81811015610907578281556001016127a4565b505050565b600019600383901b1c191660019190911b1790565b81516001600160401b038111156127ea576127ea612193565b6127fe816127f88454612497565b84612771565b602080601f83116001811461282d576000841561281b5750858301515b61282585826127bc565b865550610907565b600085815260208120601f198616915b8281101561285c5788860151825594840194600190910190840161283d565b508582101561287a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600061ffff8088168352808716602084015250846040830152608060608301526128b86080830184866124e1565b979650505050505050565b61ffff861681526080602082015260006128e16080830186886124e1565b6001600160401b0394909416604083015250606001529392505050565b6001600160401b0383111561291557612915612193565b612929836129238354612497565b83612771565b6000601f84116001811461295757600085156129455750838201355b61294f86826127bc565b8455506129b1565b600083815260209020601f19861690835b828110156129885786850135825560209485019460019092019101612968565b50868210156129a55760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6000602082840312156129ca57600080fd5b81516001600160401b038111156129e057600080fd5b8201601f810184136129f157600080fd5b80516129ff61221f826121d9565b818152856020838501011115612a1457600080fd5b610db4826020830160208601612337565b61ffff8716815260c060208201526000612a4260c0830188612363565b8281036040840152612a548188612363565b6001600160a01b0387811660608601528616608085015283810360a0850152905061254a8185612363565b60008060408385031215612a9257600080fd5b8251612a9d81611ffa565b6020939093015192949293505050565b6001600160d81b031991909116815260200190565b60008219821115612ad557612ad5612723565b50019056fea26469706673582212209f66fcbf215ccd5b466f7bbca94fb27deb3a9915741e80454e6d04704b94037564736f6c634300080f0033000000000000000000000000eac3ec0cc130f4826715187805d1b50e861f2dac0000000000000000000000003c2269811836af69497e5f486a85d7316753cf62
Deployed Bytecode
0x6080604052600436106101515760003560e01c80621d35671461015657806302b1d2391461017857806307e0db17146101ae57806310ddb137146101ce5780631b2083dc146101ee57806322f3e2d4146102235780632556e453146102485780633d8b38f61461025b57806342d65a8d1461027b5780634657b36c1461029b578063577de7d0146102bb5780635924be70146102db5780635b8c41e6146102fd5780636edb3d3c1461035a5780637533d7881461037a578063923cb952146103a75780639459b875146103c7578063950c8a74146103e95780639f38369a14610409578063a6c3d16514610429578063b353aaa714610449578063baf3292d1461047d578063cbed8b9c1461049d578063d1deba1f146104bd578063d4aae0c4146104d0578063d58a8483146104f0578063ead93c8f14610510578063eb8d72b714610531578063f5ecbdbc14610551575b600080fd5b34801561016257600080fd5b50610176610171366004611f38565b610571565b005b34801561018457600080fd5b50600354610198906001600160a01b031681565b6040516101a59190611fcb565b60405180910390f35b3480156101ba57600080fd5b506101766101c9366004611fdf565b61081a565b3480156101da57600080fd5b506101766101e9366004611fdf565b61090f565b3480156101fa57600080fd5b5061020e610209366004612012565b6109d2565b604080519283526020830191909152016101a5565b34801561022f57600080fd5b50610238610aa0565b60405190151581526020016101a5565b610176610256366004612082565b610b17565b34801561026757600080fd5b506102386102763660046120c1565b610cb8565b34801561028757600080fd5b506101766102963660046120c1565b610dbd565b3480156102a757600080fd5b506101766102b6366004612113565b610eb8565b3480156102c757600080fd5b50600254610198906001600160a01b031681565b3480156102e757600080fd5b506102f0610f10565b6040516101a59190612130565b34801561030957600080fd5b5061034c610318366004612256565b6004602090815260009384526040808520845180860184018051928152908401958401959095209452929052825290205481565b6040519081526020016101a5565b34801561036657600080fd5b506101766103753660046122b3565b6110af565b34801561038657600080fd5b5061039a610395366004611fdf565b6110e1565b6040516101a5919061238f565b3480156103b357600080fd5b50600154610198906001600160a01b031681565b3480156103d357600080fd5b506103dc61117b565b6040516101a591906123a2565b3480156103f557600080fd5b50600654610198906001600160a01b031681565b34801561041557600080fd5b5061039a610424366004611fdf565b611318565b34801561043557600080fd5b506101766104443660046120c1565b6113ff565b34801561045557600080fd5b506101987f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf6281565b34801561048957600080fd5b50610176610498366004612113565b6114f4565b3480156104a957600080fd5b506101766104b83660046123f0565b6115be565b6101766104cb366004611f38565b6116bf565b3480156104dc57600080fd5b50600054610198906001600160a01b031681565b3480156104fc57600080fd5b5061017661050b36600461242d565b611861565b34801561051c57600080fd5b5060035461023890600160a01b900460ff1681565b34801561053d57600080fd5b5061017661054c3660046120c1565b611921565b34801561055d57600080fd5b5061039a61056c36600461244a565b6119e6565b336001600160a01b037f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf6216146105ba576040516395946b5d60e01b815260040160405180910390fd5b61ffff8616600090815260056020526040812080546105d890612497565b80601f016020809104026020016040519081016040528092919081815260200182805461060490612497565b80156106515780601f1061062657610100808354040283529160200191610651565b820191906000526020600020905b81548152906001019060200180831161063457829003601f168201915b50505050509050805160001480610669575080518514155b8061069157508051602082012060405161068690889088906124d1565b604051809103902014155b156106af57604051634488ea9760e11b815260040160405180910390fd5b600080306001600160a01b0316636edb3d3c60e01b8a8a8a8a8a8a6040516024016106df9695949392919061250a565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161071d9190612557565b6000604051808303816000865af19150503d806000811461075a576040519150601f19603f3d011682016040523d82523d6000602084013e61075f565b606091505b50915091508161080f5784846040516107799291906124d1565b6040805191829003822061ffff8c16600090815260046020529190912090916107a5908b908b906124d1565b9081526040805191829003602090810183206001600160401b038b166000908152915220919091557fe183f33de2837795525b4792ca4cd60535bd77c53b7e7030060bfcf5734d6b0c90610806908b908b908b908b908b908b908990612573565b60405180910390a15b505050505050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061085b90849033906004016125d5565b600060405180830381600087803b15801561087557600080fd5b505af1158015610889573d6000803e3d6000fd5b50506040516307e0db1760e01b815261ffff851660048201527f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf626001600160a01b031692506307e0db1791506024015b600060405180830381600087803b1580156108f357600080fd5b505af1158015610907573d6000803e3d6000fd5b505050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061095090849033906004016125d5565b600060405180830381600087803b15801561096a57600080fd5b505af115801561097e573d6000803e3d6000fd5b50506040516310ddb13760e01b815261ffff851660048201527f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf626001600160a01b031692506310ddb13791506024016108d9565b600080600086866040516020016109ea9291906125ec565b60408051601f198184030181529082905263040a7bb160e41b825291506001600160a01b037f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf6216906340a7bb1090610a51908b90309086906000908c908c90600401612605565b6040805180830381865afa158015610a6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a91919061264e565b92509250509550959350505050565b6000805460405163e52223bb60e01b81526001600160a01b039091169063e52223bb90610ad1903090600401611fcb565b602060405180830381865afa158015610aee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b129190612672565b905090565b600354600160a01b900460ff16610b4157604051638bfcdf0d60e01b815260040160405180910390fd5b6003546040516370a0823160e01b815282916001600160a01b0316906370a0823190610b71903390600401611fcb565b602060405180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb2919061268f565b1015610bd15760405163ea7aa0c560e01b815260040160405180910390fd5b60008282604051602001610be69291906125ec565b60408051601f198184030181529082905260025463557856ad60e11b83529092506001600160a01b03169063aaf0ad5a90610c2790339086906004016125ec565b600060405180830381600087803b158015610c4157600080fd5b505af1158015610c55573d6000803e3d6000fd5b50505050610c7784823360006040518060200160405280600081525034611a8e565b60405182815261ffff85169033907f39a9310c2653c9e8416b19cc7ef7166640ed10fa3a958f2804c1b3d75f2081019060200160405180910390a350505050565b61ffff831660009081526005602052604081208054829190610cd990612497565b80601f0160208091040260200160405190810160405280929190818152602001828054610d0590612497565b8015610d525780601f10610d2757610100808354040283529160200191610d52565b820191906000526020600020905b815481529060010190602001808311610d3557829003601f168201915b505050505090508383905060001480610d6a57508051155b15610d88576040516302c18f6d60e31b815260040160405180910390fd5b805183148015610db4575080516020820120604051610daa90869086906124d1565b6040518091039020145b95945050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c590610dfe90849033906004016125d5565b600060405180830381600087803b158015610e1857600080fd5b505af1158015610e2c573d6000803e3d6000fd5b50506040516342d65a8d60e01b81526001600160a01b037f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf621692506342d65a8d9150610e80908790879087906004016126a8565b600060405180830381600087803b158015610e9a57600080fd5b505af1158015610eae573d6000803e3d6000fd5b5050505050505050565b6000546001600160a01b03163314610eee573360405163053e900f60e21b8152600401610ee59190611fcb565b60405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b60606000600260009054906101000a90046001600160a01b03166001600160a01b0316631ae7ec2e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8b91906126c6565b60408051600380825260808201909252919250816020015b6040805180820190915260008082526020820152815260200190600190039081610fa3575050604080518082019091526001600160d81b031983168152633a56e30760e01b60208201528151919350908390600090611004576110046126f0565b60200260200101819052506040518060400160405280826001600160d81b031916815260200163aaf0ad5a60e01b6001600160e01b03191681525082600181518110611052576110526126f0565b60200260200101819052506040518060400160405280826001600160d81b031916815260200163359fe78060e01b6001600160e01b031916815250826002815181106110a0576110a06126f0565b60200260200101819052505090565b3330146110cf576040516395946b5d60e01b815260040160405180910390fd5b6110db84848484611be0565b50505050565b600560205260009081526040902080546110fa90612497565b80601f016020809104026020016040519081016040528092919081815260200182805461112690612497565b80156111735780601f1061114857610100808354040283529160200191611173565b820191906000526020600020905b81548152906001019060200180831161115657829003601f168201915b505050505081565b60408051600280825260608083018452926020830190803683370190505090506426a4a72a2960d91b816000815181106111b7576111b76126f0565b6001600160d81b0319909216602092830291909101909101526111df64524f4c455360d81b90565b816001815181106111f2576111f26126f0565b60200260200101906001600160d81b03191690816001600160d81b031916815250506112378160008151811061122a5761122a6126f0565b6020026020010151611d12565b600260006101000a8154816001600160a01b0302191690836001600160a01b031602179055506112738160018151811061122a5761122a6126f0565b600180546001600160a01b0319166001600160a01b03928316179055600254604080516302b1d23960e01b8152905191909216916302b1d2399160048083019260209291908290030181865afa1580156112d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f59190612706565b600380546001600160a01b0319166001600160a01b039290921691909117905590565b61ffff811660009081526005602052604081208054606092919061133b90612497565b80601f016020809104026020016040519081016040528092919081815260200182805461136790612497565b80156113b45780601f10611389576101008083540402835291602001916113b4565b820191906000526020600020905b81548152906001019060200180831161139757829003601f168201915b5050505050905080516000036113dd576040516302fa5b7760e41b815260040160405180910390fd5b6113f86000601483516113f09190612739565b839190611db5565b9392505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061144090849033906004016125d5565b600060405180830381600087803b15801561145a57600080fd5b505af115801561146e573d6000803e3d6000fd5b5050505082823060405160200161148793929190612750565b60408051601f1981840301815291815261ffff86166000908152600560205220906114b290826127d1565b507f8c0400cfe2d1199b1a725c78960bcc2a344d869b80590d0f2bd005db15a572ce8484846040516114e6939291906126a8565b60405180910390a150505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061153590849033906004016125d5565b600060405180830381600087803b15801561154f57600080fd5b505af1158015611563573d6000803e3d6000fd5b5050600680546001600160a01b0319166001600160a01b03861617905550506040517f5db758e995a17ec1ad84bdef7e8c3293a0bd6179bcce400dff5d4c3d87db726b906115b2908490611fcb565b60405180910390a15050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c5906115ff90849033906004016125d5565b600060405180830381600087803b15801561161957600080fd5b505af115801561162d573d6000803e3d6000fd5b50506040516332fb62e760e21b81526001600160a01b037f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf6216925063cbed8b9c9150611685908990899089908990899060040161288a565b600060405180830381600087803b15801561169f57600080fd5b505af11580156116b3573d6000803e3d6000fd5b50505050505050505050565b61ffff861660009081526004602052604080822090516116e290889088906124d1565b90815260408051602092819003830190206001600160401b038716600090815292529020549050806117275760405163033f21d760e31b815260040160405180910390fd5b8083836040516117389291906124d1565b60405180910390201461175e57604051633d161b8760e11b815260040160405180910390fd5b61ffff8716600090815260046020526040808220905161178190899089906124d1565b90815260408051602092819003830181206001600160401b038916600090815290845282902093909355601f88018290048202830182019052868252611819918991899089908190840183828082843760009201919091525050604080516020601f8a018190048102820181019092528881528a935091508890889081908401838280828437600092019190915250611be092505050565b7fc264d91f3adc5588250e1551f547752ca0cfa8f6b530d243b9f9f4cab10ea8e587878787856040516118509594939291906128c3565b60405180910390a150505050505050565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c5906118a290849033906004016125d5565b600060405180830381600087803b1580156118bc57600080fd5b505af11580156118d0573d6000803e3d6000fd5b505060038054851515600160a01b0260ff60a01b1990911617905550506040517f0c8765b60c3fca0b25c8c97ac199bdf1a16d429abbe4213d48ba4a66d666f241906115b290841515815260200190565b60015460405163d09a20c560e01b81526b313934b233b2afb0b236b4b760a11b916001600160a01b03169063d09a20c59061196290849033906004016125d5565b600060405180830381600087803b15801561197c57600080fd5b505af1158015611990573d6000803e3d6000fd5b5050505061ffff841660009081526005602052604090206119b28385836128fe565b507ffa41487ad5d6728f0b19276fa1eddc16558578f5109fc39d2dc33c3230470dab8484846040516114e6939291906126a8565b604051633d7b2f6f60e21b815261ffff808616600483015284166024820152306044820152606481018290526060907f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf626001600160a01b03169063f5ecbdbc90608401600060405180830381865afa158015611a66573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610db491908101906129b8565b61ffff861660009081526005602052604081208054611aac90612497565b80601f0160208091040260200160405190810160405280929190818152602001828054611ad890612497565b8015611b255780601f10611afa57610100808354040283529160200191611b25565b820191906000526020600020905b815481529060010190602001808311611b0857829003601f168201915b505050505090508051600003611b4e576040516303e334ff60e51b815260040160405180910390fd5b60405162c5803160e81b81526001600160a01b037f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf62169063c5803100908490611ba5908b9086908c908c908c908c90600401612a25565b6000604051808303818588803b158015611bbe57600080fd5b505af1158015611bd2573d6000803e3d6000fd5b505050505050505050505050565b60008082806020019051810190611bf79190612a7f565b600254604051626b3fcf60e71b81529294509092506001600160a01b03169063359fe78090611c2c90309085906004016125ec565b600060405180830381600087803b158015611c4657600080fd5b505af1158015611c5a573d6000803e3d6000fd5b5050600254604051633a56e30760e01b81526001600160a01b039091169250633a56e3079150611c9090859085906004016125ec565b600060405180830381600087803b158015611caa57600080fd5b505af1158015611cbe573d6000803e3d6000fd5b505050508561ffff16826001600160a01b03167f66e72df5c00d93ba421714963fffa44e34b0f51ad224cd6966565fc089be93f883604051611d0291815260200190565b60405180910390a3505050505050565b60008054604051632d37002d60e21b815282916001600160a01b03169063b4dc00b490611d43908690600401612aad565b602060405180830381865afa158015611d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d849190612706565b90506001600160a01b038116611daf5782604051635c3fa9cd60e01b8152600401610ee59190612aad565b92915050565b606081611dc381601f612ac2565b1015611e025760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610ee5565b611e0c8284612ac2565b84511015611e505760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610ee5565b606082158015611e6f5760405191506000825260208201604052611eb9565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015611ea8578051835260209283019201611e90565b5050858452601f01601f1916604052505b50949350505050565b803561ffff81168114611ed457600080fd5b919050565b60008083601f840112611eeb57600080fd5b5081356001600160401b03811115611f0257600080fd5b602083019150836020828501011115611f1a57600080fd5b9250929050565b80356001600160401b0381168114611ed457600080fd5b60008060008060008060808789031215611f5157600080fd5b611f5a87611ec2565b955060208701356001600160401b0380821115611f7657600080fd5b611f828a838b01611ed9565b9097509550859150611f9660408a01611f21565b94506060890135915080821115611fac57600080fd5b50611fb989828a01611ed9565b979a9699509497509295939492505050565b6001600160a01b0391909116815260200190565b600060208284031215611ff157600080fd5b6113f882611ec2565b6001600160a01b038116811461200f57600080fd5b50565b60008060008060006080868803121561202a57600080fd5b61203386611ec2565b9450602086013561204381611ffa565b93506040860135925060608601356001600160401b0381111561206557600080fd5b61207188828901611ed9565b969995985093965092949392505050565b60008060006060848603121561209757600080fd5b6120a084611ec2565b925060208401356120b081611ffa565b929592945050506040919091013590565b6000806000604084860312156120d657600080fd5b6120df84611ec2565b925060208401356001600160401b038111156120fa57600080fd5b61210686828701611ed9565b9497909650939450505050565b60006020828403121561212557600080fd5b81356113f881611ffa565b602080825282518282018190526000919060409081850190868401855b8281101561218657815180516001600160d81b03191685528601516001600160e01b03191686850152928401929085019060010161214d565b5091979650505050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156121d1576121d1612193565b604052919050565b60006001600160401b038211156121f2576121f2612193565b50601f01601f191660200190565b600082601f83011261221157600080fd5b813561222461221f826121d9565b6121a9565b81815284602083860101111561223957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561226b57600080fd5b61227484611ec2565b925060208401356001600160401b0381111561228f57600080fd5b61229b86828701612200565b9250506122aa60408501611f21565b90509250925092565b600080600080608085870312156122c957600080fd5b6122d285611ec2565b935060208501356001600160401b03808211156122ee57600080fd5b6122fa88838901612200565b945061230860408801611f21565b9350606087013591508082111561231e57600080fd5b5061232b87828801612200565b91505092959194509250565b60005b8381101561235257818101518382015260200161233a565b838111156110db5750506000910152565b6000815180845261237b816020860160208601612337565b601f01601f19169290920160200192915050565b6020815260006113f86020830184612363565b6020808252825182820181905260009190848201906040850190845b818110156123e45783516001600160d81b031916835292840192918401916001016123be565b50909695505050505050565b60008060008060006080868803121561240857600080fd5b61241186611ec2565b945061204360208701611ec2565b801515811461200f57600080fd5b60006020828403121561243f57600080fd5b81356113f88161241f565b6000806000806080858703121561246057600080fd5b61246985611ec2565b935061247760208601611ec2565b9250604085013561248781611ffa565b9396929550929360600135925050565b600181811c908216806124ab57607f821691505b6020821081036124cb57634e487b7160e01b600052602260045260246000fd5b50919050565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b61ffff871681526080602082015260006125286080830187896124e1565b6001600160401b0386166040840152828103606084015261254a8185876124e1565b9998505050505050505050565b60008251612569818460208701612337565b9190910192915050565b61ffff8816815260a06020820152600061259160a08301888a6124e1565b6001600160401b038716604084015282810360608401526125b38186886124e1565b905082810360808401526125c78185612363565b9a9950505050505050505050565b9182526001600160a01b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b61ffff871681526001600160a01b038616602082015260a06040820181905260009061263390830187612363565b8515156060840152828103608084015261254a8185876124e1565b6000806040838503121561266157600080fd5b505080516020909101519092909150565b60006020828403121561268457600080fd5b81516113f88161241f565b6000602082840312156126a157600080fd5b5051919050565b61ffff84168152604060208201526000610db46040830184866124e1565b6000602082840312156126d857600080fd5b81516001600160d81b0319811681146113f857600080fd5b634e487b7160e01b600052603260045260246000fd5b60006020828403121561271857600080fd5b81516113f881611ffa565b634e487b7160e01b600052601160045260246000fd5b60008282101561274b5761274b612723565b500390565b8284823760609190911b6001600160601b0319169101908152601401919050565b601f8211156127b757600081815260208120601f850160051c810160208610156127985750805b601f850160051c820191505b81811015610907578281556001016127a4565b505050565b600019600383901b1c191660019190911b1790565b81516001600160401b038111156127ea576127ea612193565b6127fe816127f88454612497565b84612771565b602080601f83116001811461282d576000841561281b5750858301515b61282585826127bc565b865550610907565b600085815260208120601f198616915b8281101561285c5788860151825594840194600190910190840161283d565b508582101561287a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600061ffff8088168352808716602084015250846040830152608060608301526128b86080830184866124e1565b979650505050505050565b61ffff861681526080602082015260006128e16080830186886124e1565b6001600160401b0394909416604083015250606001529392505050565b6001600160401b0383111561291557612915612193565b612929836129238354612497565b83612771565b6000601f84116001811461295757600085156129455750838201355b61294f86826127bc565b8455506129b1565b600083815260209020601f19861690835b828110156129885786850135825560209485019460019092019101612968565b50868210156129a55760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6000602082840312156129ca57600080fd5b81516001600160401b038111156129e057600080fd5b8201601f810184136129f157600080fd5b80516129ff61221f826121d9565b818152856020838501011115612a1457600080fd5b610db4826020830160208601612337565b61ffff8716815260c060208201526000612a4260c0830188612363565b8281036040840152612a548188612363565b6001600160a01b0387811660608601528616608085015283810360a0850152905061254a8185612363565b60008060408385031215612a9257600080fd5b8251612a9d81611ffa565b6020939093015192949293505050565b6001600160d81b031991909116815260200190565b60008219821115612ad557612ad5612723565b50019056fea26469706673582212209f66fcbf215ccd5b466f7bbca94fb27deb3a9915741e80454e6d04704b94037564736f6c634300080f0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000eac3ec0cc130f4826715187805d1b50e861f2dac0000000000000000000000003c2269811836af69497e5f486a85d7316753cf62
-----Decoded View---------------
Arg [0] : kernel_ (address): 0xeac3eC0CC130f4826715187805d1B50e861F2DaC
Arg [1] : endpoint_ (address): 0x3c2269811836af69497E5F486A85D7316753cf62
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000eac3ec0cc130f4826715187805d1b50e861f2dac
Arg [1] : 0000000000000000000000003c2269811836af69497e5f486a85d7316753cf62
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.