More Info
Private Name Tags
ContractCreator
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
21472845 | 4 days ago | 0.000159 ETH | ||||
21472845 | 4 days ago | 0.000159 ETH | ||||
21449491 | 8 days ago | 0.000159 ETH | ||||
21449491 | 8 days ago | 0.000159 ETH | ||||
21441716 | 9 days ago | 0.000159 ETH | ||||
21441716 | 9 days ago | 0.000159 ETH | ||||
21439388 | 9 days ago | 0.0001734 ETH | ||||
21439388 | 9 days ago | 0.0001734 ETH | ||||
21420882 | 12 days ago | 0.000159 ETH | ||||
21420882 | 12 days ago | 0.000159 ETH | ||||
21418126 | 12 days ago | 0.000159 ETH | ||||
21418126 | 12 days ago | 0.000159 ETH | ||||
21418041 | 12 days ago | 0.000159 ETH | ||||
21418041 | 12 days ago | 0.000159 ETH | ||||
21417805 | 12 days ago | 0.000159 ETH | ||||
21417805 | 12 days ago | 0.000159 ETH | ||||
21414273 | 12 days ago | 0.0001734 ETH | ||||
21414273 | 12 days ago | 0.0001734 ETH | ||||
21383695 | 17 days ago | 0.000159 ETH | ||||
21383695 | 17 days ago | 0.000159 ETH | ||||
21369976 | 19 days ago | 0.000159 ETH | ||||
21369976 | 19 days ago | 0.000159 ETH | ||||
21361014 | 20 days ago | 0.0001782 ETH | ||||
21361014 | 20 days ago | 0.0001782 ETH | ||||
21359786 | 20 days ago | 0.0001782 ETH |
Loading...
Loading
Contract Name:
CrossChainVaultApp
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 300 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./CrossChainERC20.sol"; import "./ICrossChainVault.sol"; import "../op/IMultichainEndpoint.sol"; import "../op/celer/message/framework/MessageApp.sol"; contract CrossChainVaultApp is MessageApp, Ownable { using SafeERC20 for ERC20; enum CrossChainVaultMessageType { LockAndMint, BurnAndUnlock } struct SetAllowedSender { address sender; uint64 srcChainId; bool isAllowed; } struct CrossChainAssetData { bool isDataSet; address token; string name; string symbol; uint8 decimals; uint64 chainId; } event SetAuthorisedSender(address indexed sender, uint64 indexed chainId, bool isSet); event ActualEndpointChange(address prev, address updated); event EndpointExecutionReverted(bytes reason); ICrossChainVault public immutable vault; IMultichainEndpoint public endpoint; mapping(uint64 => mapping(address => CrossChainERC20)) public mintedTokenByOriginal; mapping(uint64 => mapping(CrossChainERC20 => address)) public originalTokenByMinted; mapping(address => mapping(uint64 => bool)) public allowedSenders; mapping(uint64 => bool) public allowedSenderSetup; mapping(address => mapping(uint64 => CrossChainAssetData)) public crossChainAssetsData; constructor(address _vault, address _messageBus) MessageApp(_messageBus) { vault = ICrossChainVault(_vault); } function setActualEndpoint(address _endpoint) public onlyOwner { require(address(endpoint) == address(0), "The endpoint is already configured"); emit ActualEndpointChange(address(endpoint), _endpoint); endpoint = IMultichainEndpoint(_endpoint); } function setCrossChainAssets(CrossChainAssetData[] calldata assets) public onlyOwner { for (uint i = 0; i < assets.length; i++) { crossChainAssetsData[assets[i].token][assets[i].chainId] = assets[i]; } } function setAllowedSenders(SetAllowedSender[] calldata senders) public onlyOwner { for (uint i = 0; i < senders.length; i++) { // We can't add new senders for same chain id otherwise it would be dangerous require(!allowedSenderSetup[senders[i].srcChainId], "Sender is already setup"); emit SetAuthorisedSender(senders[i].sender, senders[i].srcChainId, senders[i].isAllowed); allowedSenders[senders[i].sender][senders[i].srcChainId] = senders[i].isAllowed; allowedSenderSetup[senders[i].srcChainId] = true; } } function executeMessage( address srcContract, uint64 _srcChainId, bytes calldata _message, address ) external payable override onlyMessageBus returns (ExecutionStatus) { require(allowedSenders[srcContract][_srcChainId], "Unauthorised sender"); (bytes memory lockData, bytes memory _data) = abi.decode(_message, (bytes, bytes)); (address token, uint256 amount) = _processVaultCommand(_srcChainId, lockData); ERC20(token).safeTransfer(address(endpoint), amount); IMultichainEndpoint.CallbackExecutionStatus status = IMultichainEndpoint.CallbackExecutionStatus.Failed; try endpoint.executeMessageWithTransfer( token, amount, _srcChainId, _data ) returns (IMultichainEndpoint.CallbackExecutionStatus _status) { status = _status; } catch (bytes memory reason) { emit EndpointExecutionReverted(reason); status = endpoint.executeMessageWithTransferFallback( token, amount, _data ); } if (status == IMultichainEndpoint.CallbackExecutionStatus.Success) { return ExecutionStatus.Success; } else if (status == IMultichainEndpoint.CallbackExecutionStatus.Failed) { return ExecutionStatus.Fail; } else if (status == IMultichainEndpoint.CallbackExecutionStatus.Retry) { return ExecutionStatus.Retry; } return ExecutionStatus.Fail; } function _processVaultCommand(uint64 srcChainId, bytes memory rawCommand) private returns (address token, uint256 amt) { (uint8 _type, address srcAddress, uint256 amount) = abi.decode(rawCommand, (uint8, address, uint256)); CrossChainVaultMessageType cmdType = CrossChainVaultMessageType(_type); amt = amount; if (cmdType == CrossChainVaultMessageType.LockAndMint) { CrossChainAssetData memory data = crossChainAssetsData[srcAddress][srcChainId]; require(data.isDataSet, "Metadata is not set"); token = _mintTokens(CrossChainERC20.CrossChainERC20Config( data.name, data.symbol, data.decimals, srcChainId, srcAddress ), amount); } else if (cmdType == CrossChainVaultMessageType.BurnAndUnlock) { vault.unlock(srcAddress, amount); token = srcAddress; } else { revert(); } } function _mintTokens(CrossChainERC20.CrossChainERC20Config memory originalTokenDetails, uint256 amount) private returns (address) { CrossChainERC20 minted = mintedTokenByOriginal[originalTokenDetails.originalChainId][originalTokenDetails.originalAddress]; if (address(minted) == address(0)) { minted = new CrossChainERC20(originalTokenDetails); mintedTokenByOriginal[originalTokenDetails.originalChainId][originalTokenDetails.originalAddress] = minted; originalTokenByMinted[originalTokenDetails.originalChainId][minted] = originalTokenDetails.originalAddress; } minted.mint(address(this), amount); return address(minted); } receive() external payable {} function lockAndMint(address to, uint64 chainId, address token, uint256 amount, bytes memory message) public payable { require(msg.sender == address(endpoint), "Invalid endpoint"); ERC20(token).safeTransferFrom(msg.sender, address(this), amount); ERC20(token).safeIncreaseAllowance(address(vault), amount); amount = vault.lock(token, amount); bytes memory lockData = abi.encode(uint8(CrossChainVaultMessageType.LockAndMint), token, amount); bytes memory payload = abi.encode(lockData, message); sendMessage(to, chainId, payload, IMessageBus(messageBus).calcFee(payload)); } function burnAndUnlock(address to, uint64 chainId, address token, uint256 amount, bytes memory message) public payable { require(msg.sender == address(endpoint), "Invalid endpoint"); require(originalTokenByMinted[chainId][CrossChainERC20(token)] != address(0), "Invalid cross-chain token"); ERC20(token).safeTransferFrom(msg.sender, address(this), amount); CrossChainERC20 crossChainToken = CrossChainERC20(token); crossChainToken.burn(address(this), amount); bytes memory unlockData = abi.encode(uint8(CrossChainVaultMessageType.BurnAndUnlock), crossChainToken.originalAddress(), amount); bytes memory payload = abi.encode(unlockData, message); sendMessage(to, chainId, payload, IMessageBus(messageBus).calcFee(payload)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ 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); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract CrossChainERC20 is IERC20 { struct CrossChainERC20Config { string name; string symbol; uint8 decimals; uint64 originalChainId; address originalAddress; } mapping(address => uint256) internal _balances; mapping(address => mapping(address => uint256)) internal _allowances; string public name; string public symbol; uint8 public decimals; address public originalAddress; uint64 public originalChainId; address public immutable deployer; uint256 public totalSupply; constructor(CrossChainERC20Config memory _config) { name = _config.name; symbol = _config.symbol; decimals = _config.decimals; originalChainId = _config.originalChainId; originalAddress = _config.originalAddress; deployer = msg.sender; } function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } function _approve( address owner, address spender, uint256 amount ) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; } function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = msg.sender; _approve(owner, spender, amount); return true; } function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = _allowances[owner][spender]; if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; } _balances[to] += amount; } function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = msg.sender; _transfer(owner, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = msg.sender; _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } function mint(address to, uint256 amount) public { require(msg.sender == deployer); _balances[to] += amount; totalSupply += amount; } function burn(address from, uint256 amount) public { require(msg.sender == deployer); _balances[from] -= amount; totalSupply -= amount; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; interface ICrossChainVault { function lock(address asset, uint256 amount) external returns (uint256); function unlock(address asset, uint256 amount) external; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IBridge { function send( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage ) external; function sendNative( address _receiver, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage ) external payable; function relay( bytes calldata _relayRequest, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external; function transfers(bytes32 transferId) external view returns (bool); function withdraws(bytes32 withdrawId) external view returns (bool); function withdraw( bytes calldata _wdmsg, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external; /** * @notice Verifies that a message is signed by a quorum among the signers. * @param _msg signed message * @param _sigs list of signatures sorted by signer addresses in ascending order * @param _signers sorted list of current signers * @param _powers powers of current signers */ function verifySigs( bytes memory _msg, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external view; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.17; interface IDelayedTransfer { struct delayedTransfer { address receiver; address token; uint256 amount; uint256 timestamp; } function delayedTransfers(bytes32 transferId) external view returns (delayedTransfer memory); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IOriginalTokenVault { /** * @notice Lock original tokens to trigger mint at a remote chain's PeggedTokenBridge * @param _token local token address * @param _amount locked token amount * @param _mintChainId destination chainId to mint tokens * @param _mintAccount destination account to receive minted tokens * @param _nonce user input to guarantee unique depositId */ function deposit( address _token, uint256 _amount, uint64 _mintChainId, address _mintAccount, uint64 _nonce ) external; /** * @notice Lock native token as original token to trigger mint at a remote chain's PeggedTokenBridge * @param _amount locked token amount * @param _mintChainId destination chainId to mint tokens * @param _mintAccount destination account to receive minted tokens * @param _nonce user input to guarantee unique depositId */ function depositNative( uint256 _amount, uint64 _mintChainId, address _mintAccount, uint64 _nonce ) external payable; /** * @notice Withdraw locked original tokens triggered by a burn at a remote chain's PeggedTokenBridge. * @param _request The serialized Withdraw protobuf. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the bridge's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function withdraw( bytes calldata _request, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external; function records(bytes32 recordId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IOriginalTokenVaultV2 { /** * @notice Lock original tokens to trigger mint at a remote chain's PeggedTokenBridge * @param _token local token address * @param _amount locked token amount * @param _mintChainId destination chainId to mint tokens * @param _mintAccount destination account to receive minted tokens * @param _nonce user input to guarantee unique depositId */ function deposit( address _token, uint256 _amount, uint64 _mintChainId, address _mintAccount, uint64 _nonce ) external returns (bytes32); /** * @notice Lock native token as original token to trigger mint at a remote chain's PeggedTokenBridge * @param _amount locked token amount * @param _mintChainId destination chainId to mint tokens * @param _mintAccount destination account to receive minted tokens * @param _nonce user input to guarantee unique depositId */ function depositNative( uint256 _amount, uint64 _mintChainId, address _mintAccount, uint64 _nonce ) external payable returns (bytes32); /** * @notice Withdraw locked original tokens triggered by a burn at a remote chain's PeggedTokenBridge. * @param _request The serialized Withdraw protobuf. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the bridge's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function withdraw( bytes calldata _request, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external returns (bytes32); function records(bytes32 recordId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IPeggedTokenBridge { /** * @notice Burn tokens to trigger withdrawal at a remote chain's OriginalTokenVault * @param _token local token address * @param _amount locked token amount * @param _withdrawAccount account who withdraw original tokens on the remote chain * @param _nonce user input to guarantee unique depositId */ function burn( address _token, uint256 _amount, address _withdrawAccount, uint64 _nonce ) external; /** * @notice Mint tokens triggered by deposit at a remote chain's OriginalTokenVault. * @param _request The serialized Mint protobuf. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function mint( bytes calldata _request, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external; function records(bytes32 recordId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IPeggedTokenBridgeV2 { /** * @notice Burn pegged tokens to trigger a cross-chain withdrawal of the original tokens at a remote chain's * OriginalTokenVault, or mint at another remote chain * @param _token The pegged token address. * @param _amount The amount to burn. * @param _toChainId If zero, withdraw from original vault; otherwise, the remote chain to mint tokens. * @param _toAccount The account to receive tokens on the remote chain * @param _nonce A number to guarantee unique depositId. Can be timestamp in practice. */ function burn( address _token, uint256 _amount, uint64 _toChainId, address _toAccount, uint64 _nonce ) external returns (bytes32); // same with `burn` above, use openzeppelin ERC20Burnable interface function burnFrom( address _token, uint256 _amount, uint64 _toChainId, address _toAccount, uint64 _nonce ) external returns (bytes32); /** * @notice Mint tokens triggered by deposit at a remote chain's OriginalTokenVault. * @param _request The serialized Mint protobuf. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function mint( bytes calldata _request, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external returns (bytes32); function records(bytes32 recordId) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface ISigsVerifier { /** * @notice Verifies that a message is signed by a quorum among the signers. * @param _msg signed message * @param _sigs list of signatures sorted by signer addresses in ascending order * @param _signers sorted list of current signers * @param _powers powers of current signers */ function verifySigs( bytes memory _msg, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external view; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; library Utils { // https://ethereum.stackexchange.com/a/83577 // https://github.com/Uniswap/v3-periphery/blob/v1.0.0/contracts/base/Multicall.sol function getRevertMsg(bytes memory _returnData) internal pure returns (string memory) { // If the _res length is less than 68, then the transaction failed silently (without a revert message) if (_returnData.length < 68) return "Transaction reverted silently"; assembly { // Slice the sighash. _returnData := add(_returnData, 0x04) } return abi.decode(_returnData, (string)); // All that remains is the revert string } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; import "./MessageSenderApp.sol"; import "./MessageReceiverApp.sol"; abstract contract MessageApp is MessageSenderApp, MessageReceiverApp { constructor(address _messageBus) { messageBus = _messageBus; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; abstract contract MessageBusAddress { address public messageBus; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; import "../interfaces/IMessageReceiverApp.sol"; import "../libraries/MsgDataTypes.sol"; import "./MessageBusAddress.sol"; abstract contract MessageReceiverApp is IMessageReceiverApp, MessageBusAddress { modifier onlyMessageBus() { require(msg.sender == messageBus, "caller is not message bus"); _; } // Add abort prefix in the reason string for require or revert. // This will abort (revert) the message execution without markig it as failed state, // making it possible to retry later. function _abortReason(string memory reason) internal pure returns (string memory) { return MsgDataTypes.abortReason(reason); } /** * @notice Called by MessageBus to execute a message * @param _sender The address of the source app contract * @param _srcChainId The source chain ID where the transfer is originated from * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _executor Address who called the MessageBus execution function */ function executeMessage( address _sender, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable virtual override onlyMessageBus returns (ExecutionStatus) {} // execute message from non-evm chain with bytes for sender address, // otherwise same as above. function executeMessage( bytes calldata _sender, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable virtual override onlyMessageBus returns (ExecutionStatus) {} /** * @notice Called by MessageBus to execute a message with an associated token transfer. * The contract is guaranteed to have received the right amount of tokens before this function is called. * @param _sender The address of the source app contract * @param _token The address of the token that comes out of the bridge * @param _amount The amount of tokens received at this contract through the cross-chain bridge. * @param _srcChainId The source chain ID where the transfer is originated from * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransfer( address _sender, address _token, uint256 _amount, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable virtual override onlyMessageBus returns (ExecutionStatus) {} /** * @notice Only called by MessageBus if * 1. executeMessageWithTransfer reverts, or * 2. executeMessageWithTransfer returns ExecutionStatus.Fail * The contract is guaranteed to have received the right amount of tokens before this function is called. * @param _sender The address of the source app contract * @param _token The address of the token that comes out of the bridge * @param _amount The amount of tokens received at this contract through the cross-chain bridge. * @param _srcChainId The source chain ID where the transfer is originated from * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransferFallback( address _sender, address _token, uint256 _amount, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable virtual override onlyMessageBus returns (ExecutionStatus) {} /** * @notice Called by MessageBus to process refund of the original transfer from this contract. * The contract is guaranteed to have received the refund before this function is called. * @param _token The token address of the original transfer * @param _amount The amount of the original transfer * @param _message The same message associated with the original transfer * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransferRefund( address _token, uint256 _amount, bytes calldata _message, address _executor ) external payable virtual override onlyMessageBus returns (ExecutionStatus) {} }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../libraries/MsgDataTypes.sol"; import "../libraries/MessageSenderLib.sol"; import "../messagebus/MessageBus.sol"; import "./MessageBusAddress.sol"; abstract contract MessageSenderApp is MessageBusAddress { using SafeERC20 for IERC20; // ============== Utility functions called by apps ============== /** * @notice Sends a message to a contract on another chain. * Sender needs to make sure the uniqueness of the message Id, which is computed as * hash(type.MessageOnly, sender, receiver, srcChainId, srcTxHash, dstChainId, message). * If messages with the same Id are sent, only one of them will succeed at dst chain. * @param _receiver The address of the destination app contract. * @param _dstChainId The destination chain ID. * @param _message Arbitrary message bytes to be decoded by the destination app contract. * @param _fee The fee amount to pay to MessageBus. */ function sendMessage( address _receiver, uint64 _dstChainId, bytes memory _message, uint256 _fee ) internal { MessageSenderLib.sendMessage(_receiver, _dstChainId, _message, messageBus, _fee); } // Send message to non-evm chain with bytes for receiver address, // otherwise same as above. function sendMessage( bytes calldata _receiver, uint64 _dstChainId, bytes memory _message, uint256 _fee ) internal { MessageSenderLib.sendMessage(_receiver, _dstChainId, _message, messageBus, _fee); } /** * @notice Sends a message associated with a transfer to a contract on another chain. * @param _receiver The address of the destination app contract. * @param _token The address of the token to be sent. * @param _amount The amount of tokens to be sent. * @param _dstChainId The destination chain ID. * @param _nonce A number input to guarantee uniqueness of transferId. Can be timestamp in practice. * @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%. * Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least * (100% - max slippage percentage) * amount or the transfer can be refunded. * Only applicable to the {MsgDataTypes.BridgeSendType.Liquidity}. * @param _message Arbitrary message bytes to be decoded by the destination app contract. * If message is empty, only the token transfer will be sent * @param _bridgeSendType One of the {BridgeSendType} enum. * @param _fee The fee amount to pay to MessageBus. * @return The transfer ID. */ function sendMessageWithTransfer( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage, bytes memory _message, MsgDataTypes.BridgeSendType _bridgeSendType, uint256 _fee ) internal returns (bytes32) { return MessageSenderLib.sendMessageWithTransfer( _receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage, _message, _bridgeSendType, messageBus, _fee ); } /** * @notice Sends a token transfer via a bridge. * @dev sendMessageWithTransfer with empty message * @param _receiver The address of the destination app contract. * @param _token The address of the token to be sent. * @param _amount The amount of tokens to be sent. * @param _dstChainId The destination chain ID. * @param _nonce A number input to guarantee uniqueness of transferId. Can be timestamp in practice. * @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%. * Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least * (100% - max slippage percentage) * amount or the transfer can be refunded. * Only applicable to the {MsgDataTypes.BridgeSendType.Liquidity}. * @param _bridgeSendType One of the {BridgeSendType} enum. */ function sendTokenTransfer( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage, MsgDataTypes.BridgeSendType _bridgeSendType ) internal returns (bytes32) { return MessageSenderLib.sendMessageWithTransfer( _receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage, "", // empty message, which will not trigger sendMessage _bridgeSendType, messageBus, 0 ); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; import "../libraries/MsgDataTypes.sol"; interface IMessageBus { /** * @notice Send a message to a contract on another chain. * Sender needs to make sure the uniqueness of the message Id, which is computed as * hash(type.MessageOnly, sender, receiver, srcChainId, srcTxHash, dstChainId, message). * If messages with the same Id are sent, only one of them will succeed at dst chain.. * A fee is charged in the native gas token. * @param _receiver The address of the destination app contract. * @param _dstChainId The destination chain ID. * @param _message Arbitrary message bytes to be decoded by the destination app contract. */ function sendMessage( address _receiver, uint256 _dstChainId, bytes calldata _message ) external payable; // same as above, except that receiver is an non-evm chain address, function sendMessage( bytes calldata _receiver, uint256 _dstChainId, bytes calldata _message ) external payable; /** * @notice Send a message associated with a token transfer to a contract on another chain. * If messages with the same srcTransferId are sent, only one of them will succeed at dst chain.. * A fee is charged in the native token. * @param _receiver The address of the destination app contract. * @param _dstChainId The destination chain ID. * @param _srcBridge The bridge contract to send the transfer with. * @param _srcTransferId The transfer ID. * @param _dstChainId The destination chain ID. * @param _message Arbitrary message bytes to be decoded by the destination app contract. */ function sendMessageWithTransfer( address _receiver, uint256 _dstChainId, address _srcBridge, bytes32 _srcTransferId, bytes calldata _message ) external payable; /** * @notice Execute a message not associated with a transfer. * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function executeMessage( bytes calldata _message, MsgDataTypes.RouteInfo calldata _route, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external payable; /** * @notice Execute a message with a successful transfer. * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _transfer The transfer info. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function executeMessageWithTransfer( bytes calldata _message, MsgDataTypes.TransferInfo calldata _transfer, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external payable; /** * @notice Execute a message with a refunded transfer. * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _transfer The transfer info. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function executeMessageWithTransferRefund( bytes calldata _message, // the same message associated with the original transfer MsgDataTypes.TransferInfo calldata _transfer, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external payable; /** * @notice Withdraws message fee in the form of native gas token. * @param _account The address receiving the fee. * @param _cumulativeFee The cumulative fee credited to the account. Tracked by SGN. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A withdrawal must be * signed-off by +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function withdrawFee( address _account, uint256 _cumulativeFee, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external; /** * @notice Calculates the required fee for the message. * @param _message Arbitrary message bytes to be decoded by the destination app contract. @ @return The required fee. */ function calcFee(bytes calldata _message) external view returns (uint256); function liquidityBridge() external view returns (address); function pegBridge() external view returns (address); function pegBridgeV2() external view returns (address); function pegVault() external view returns (address); function pegVaultV2() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; interface IMessageReceiverApp { enum ExecutionStatus { Fail, // execution failed, finalized Success, // execution succeeded, finalized Retry // execution rejected, can retry later } /** * @notice Called by MessageBus to execute a message * @param _sender The address of the source app contract * @param _srcChainId The source chain ID where the transfer is originated from * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _executor Address who called the MessageBus execution function */ function executeMessage( address _sender, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable returns (ExecutionStatus); // same as above, except that sender is an non-evm chain address, // otherwise same as above. function executeMessage( bytes calldata _sender, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable returns (ExecutionStatus); /** * @notice Called by MessageBus to execute a message with an associated token transfer. * The contract is guaranteed to have received the right amount of tokens before this function is called. * @param _sender The address of the source app contract * @param _token The address of the token that comes out of the bridge * @param _amount The amount of tokens received at this contract through the cross-chain bridge. * @param _srcChainId The source chain ID where the transfer is originated from * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransfer( address _sender, address _token, uint256 _amount, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable returns (ExecutionStatus); /** * @notice Only called by MessageBus if * 1. executeMessageWithTransfer reverts, or * 2. executeMessageWithTransfer returns ExecutionStatus.Fail * The contract is guaranteed to have received the right amount of tokens before this function is called. * @param _sender The address of the source app contract * @param _token The address of the token that comes out of the bridge * @param _amount The amount of tokens received at this contract through the cross-chain bridge. * @param _srcChainId The source chain ID where the transfer is originated from * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransferFallback( address _sender, address _token, uint256 _amount, uint64 _srcChainId, bytes calldata _message, address _executor ) external payable returns (ExecutionStatus); /** * @notice Called by MessageBus to process refund of the original transfer from this contract. * The contract is guaranteed to have received the refund before this function is called. * @param _token The token address of the original transfer * @param _amount The amount of the original transfer * @param _message The same message associated with the original transfer * @param _executor Address who called the MessageBus execution function */ function executeMessageWithTransferRefund( address _token, uint256 _amount, bytes calldata _message, address _executor ) external payable returns (ExecutionStatus); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "../../interfaces/IBridge.sol"; import "../../interfaces/IOriginalTokenVault.sol"; import "../../interfaces/IOriginalTokenVaultV2.sol"; import "../../interfaces/IPeggedTokenBridge.sol"; import "../../interfaces/IPeggedTokenBridgeV2.sol"; import "../interfaces/IMessageBus.sol"; import "./MsgDataTypes.sol"; library MessageSenderLib { using SafeERC20 for IERC20; // ============== Internal library functions called by apps ============== /** * @notice Sends a message to an app on another chain via MessageBus without an associated transfer. * @param _receiver The address of the destination app contract. * @param _dstChainId The destination chain ID. * @param _message Arbitrary message bytes to be decoded by the destination app contract. * @param _messageBus The address of the MessageBus on this chain. * @param _fee The fee amount to pay to MessageBus. */ function sendMessage( address _receiver, uint64 _dstChainId, bytes memory _message, address _messageBus, uint256 _fee ) internal { IMessageBus(_messageBus).sendMessage{value: _fee}(_receiver, _dstChainId, _message); } // Send message to non-evm chain with bytes for receiver address, // otherwise same as above. function sendMessage( bytes calldata _receiver, uint64 _dstChainId, bytes memory _message, address _messageBus, uint256 _fee ) internal { IMessageBus(_messageBus).sendMessage{value: _fee}(_receiver, _dstChainId, _message); } /** * @notice Sends a message to an app on another chain via MessageBus with an associated transfer. * @param _receiver The address of the destination app contract. * @param _token The address of the token to be sent. * @param _amount The amount of tokens to be sent. * @param _dstChainId The destination chain ID. * @param _nonce A number input to guarantee uniqueness of transferId. Can be timestamp in practice. * @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%. * Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least (100% - max slippage percentage) * amount or the * transfer can be refunded. Only applicable to the {MsgDataTypes.BridgeSendType.Liquidity}. * @param _message Arbitrary message bytes to be decoded by the destination app contract. * @param _bridgeSendType One of the {MsgDataTypes.BridgeSendType} enum. * @param _messageBus The address of the MessageBus on this chain. * @param _fee The fee amount to pay to MessageBus. * @return The transfer ID. */ function sendMessageWithTransfer( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage, bytes memory _message, MsgDataTypes.BridgeSendType _bridgeSendType, address _messageBus, uint256 _fee ) internal returns (bytes32) { (bytes32 transferId, address bridge) = sendTokenTransfer( _receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage, _bridgeSendType, _messageBus ); if (_message.length > 0) { IMessageBus(_messageBus).sendMessageWithTransfer{value: _fee}( _receiver, _dstChainId, bridge, transferId, _message ); } return transferId; } /** * @notice Sends a token transfer via a bridge. * @param _receiver The address of the destination app contract. * @param _token The address of the token to be sent. * @param _amount The amount of tokens to be sent. * @param _dstChainId The destination chain ID. * @param _nonce A number input to guarantee uniqueness of transferId. Can be timestamp in practice. * @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%. * Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least (100% - max slippage percentage) * amount or the * transfer can be refunded. * @param _bridgeSendType One of the {MsgDataTypes.BridgeSendType} enum. */ function sendTokenTransfer( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce, uint32 _maxSlippage, MsgDataTypes.BridgeSendType _bridgeSendType, address _messageBus ) internal returns (bytes32 transferId, address bridge) { if (_bridgeSendType == MsgDataTypes.BridgeSendType.Liquidity) { bridge = IMessageBus(_messageBus).liquidityBridge(); IERC20(_token).safeIncreaseAllowance(bridge, _amount); IBridge(bridge).send(_receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage); transferId = computeLiqBridgeTransferId(_receiver, _token, _amount, _dstChainId, _nonce); } else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegDeposit) { bridge = IMessageBus(_messageBus).pegVault(); IERC20(_token).safeIncreaseAllowance(bridge, _amount); IOriginalTokenVault(bridge).deposit(_token, _amount, _dstChainId, _receiver, _nonce); transferId = computePegV1DepositId(_receiver, _token, _amount, _dstChainId, _nonce); } else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegBurn) { bridge = IMessageBus(_messageBus).pegBridge(); IERC20(_token).safeIncreaseAllowance(bridge, _amount); IPeggedTokenBridge(bridge).burn(_token, _amount, _receiver, _nonce); // handle cases where certain tokens do not spend allowance for role-based burn IERC20(_token).safeApprove(bridge, 0); transferId = computePegV1BurnId(_receiver, _token, _amount, _nonce); } else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2Deposit) { bridge = IMessageBus(_messageBus).pegVaultV2(); IERC20(_token).safeIncreaseAllowance(bridge, _amount); transferId = IOriginalTokenVaultV2(bridge).deposit(_token, _amount, _dstChainId, _receiver, _nonce); } else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2Burn) { bridge = IMessageBus(_messageBus).pegBridgeV2(); IERC20(_token).safeIncreaseAllowance(bridge, _amount); transferId = IPeggedTokenBridgeV2(bridge).burn(_token, _amount, _dstChainId, _receiver, _nonce); // handle cases where certain tokens do not spend allowance for role-based burn IERC20(_token).safeApprove(bridge, 0); } else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2BurnFrom) { bridge = IMessageBus(_messageBus).pegBridgeV2(); IERC20(_token).safeIncreaseAllowance(bridge, _amount); transferId = IPeggedTokenBridgeV2(bridge).burnFrom(_token, _amount, _dstChainId, _receiver, _nonce); // handle cases where certain tokens do not spend allowance for role-based burn IERC20(_token).safeApprove(bridge, 0); } else { revert("bridge type not supported"); } } function computeLiqBridgeTransferId( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce ) internal view returns (bytes32) { return keccak256( abi.encodePacked(address(this), _receiver, _token, _amount, _dstChainId, _nonce, uint64(block.chainid)) ); } function computePegV1DepositId( address _receiver, address _token, uint256 _amount, uint64 _dstChainId, uint64 _nonce ) internal view returns (bytes32) { return keccak256( abi.encodePacked(address(this), _token, _amount, _dstChainId, _receiver, _nonce, uint64(block.chainid)) ); } function computePegV1BurnId( address _receiver, address _token, uint256 _amount, uint64 _nonce ) internal view returns (bytes32) { return keccak256(abi.encodePacked(address(this), _token, _amount, _receiver, _nonce, uint64(block.chainid))); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.0; library MsgDataTypes { string constant ABORT_PREFIX = "MSG::ABORT:"; // Add abort prefix in the reason string for require or revert. // This will abort (revert) the message execution without markig it as failed state, // making it possible to retry later. function abortReason(string memory reason) internal pure returns (string memory) { return string.concat(MsgDataTypes.ABORT_PREFIX, reason); } // bridge operation type at the sender side (src chain) enum BridgeSendType { Null, Liquidity, PegDeposit, PegBurn, PegV2Deposit, PegV2Burn, PegV2BurnFrom } // bridge operation type at the receiver side (dst chain) enum TransferType { Null, LqRelay, // relay through liquidity bridge LqWithdraw, // withdraw from liquidity bridge PegMint, // mint through pegged token bridge PegWithdraw, // withdraw from original token vault PegV2Mint, // mint through pegged token bridge v2 PegV2Withdraw // withdraw from original token vault v2 } enum MsgType { MessageWithTransfer, MessageOnly } enum TxStatus { Null, Success, Fail, Fallback, Pending // transient state within a transaction } struct TransferInfo { TransferType t; address sender; address receiver; address token; uint256 amount; uint64 wdseq; // only needed for LqWithdraw (refund) uint64 srcChainId; bytes32 refId; bytes32 srcTxHash; // src chain msg tx hash } struct RouteInfo { address sender; address receiver; uint64 srcChainId; bytes32 srcTxHash; // src chain msg tx hash } // used for msg from non-evm chains with longer-bytes address struct RouteInfo2 { bytes sender; address receiver; uint64 srcChainId; bytes32 srcTxHash; } // combination of RouteInfo and RouteInfo2 for easier processing struct Route { address sender; // from RouteInfo bytes senderBytes; // from RouteInfo2 address receiver; uint64 srcChainId; bytes32 srcTxHash; } struct MsgWithTransferExecutionParams { bytes message; TransferInfo transfer; bytes[] sigs; address[] signers; uint256[] powers; } struct BridgeTransferParams { bytes request; bytes[] sigs; address[] signers; uint256[] powers; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.17; import "./MessageBusSender.sol"; import "./MessageBusReceiver.sol"; contract MessageBus is MessageBusSender, MessageBusReceiver { constructor( ISigsVerifier _sigsVerifier, address _liquidityBridge, address _pegBridge, address _pegVault, address _pegBridgeV2, address _pegVaultV2 ) MessageBusSender(_sigsVerifier) MessageBusReceiver(_liquidityBridge, _pegBridge, _pegVault, _pegBridgeV2, _pegVaultV2) {} // this is only to be called by Proxy via delegateCall as initOwner will require _owner is 0. // so calling init on this contract directly will guarantee to fail function init( address _liquidityBridge, address _pegBridge, address _pegVault, address _pegBridgeV2, address _pegVaultV2 ) external { // MUST manually call ownable init and must only call once initOwner(); // we don't need sender init as _sigsVerifier is immutable so already in the deployed code initReceiver(_liquidityBridge, _pegBridge, _pegVault, _pegBridgeV2, _pegVaultV2); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.17; import "../libraries/MsgDataTypes.sol"; import "../interfaces/IMessageReceiverApp.sol"; import "../../interfaces/IBridge.sol"; import "../../interfaces/IOriginalTokenVault.sol"; import "../../interfaces/IOriginalTokenVaultV2.sol"; import "../../interfaces/IPeggedTokenBridge.sol"; import "../../interfaces/IPeggedTokenBridgeV2.sol"; import "../../interfaces/IDelayedTransfer.sol"; import "../../safeguard/Ownable.sol"; import "../../libraries/Utils.sol"; contract MessageBusReceiver is Ownable { mapping(bytes32 => MsgDataTypes.TxStatus) public executedMessages; address public liquidityBridge; // liquidity bridge address address public pegBridge; // peg bridge address address public pegVault; // peg original vault address address public pegBridgeV2; // peg bridge address address public pegVaultV2; // peg original vault address // minimum amount of gas needed by this contract before it tries to // deliver a message to the target contract. uint256 public preExecuteMessageGasUsage; event Executed( MsgDataTypes.MsgType msgType, bytes32 msgId, MsgDataTypes.TxStatus status, address indexed receiver, uint64 srcChainId, bytes32 srcTxHash ); event NeedRetry(MsgDataTypes.MsgType msgType, bytes32 msgId, uint64 srcChainId, bytes32 srcTxHash); event CallReverted(string reason); // help debug event LiquidityBridgeUpdated(address liquidityBridge); event PegBridgeUpdated(address pegBridge); event PegVaultUpdated(address pegVault); event PegBridgeV2Updated(address pegBridgeV2); event PegVaultV2Updated(address pegVaultV2); constructor( address _liquidityBridge, address _pegBridge, address _pegVault, address _pegBridgeV2, address _pegVaultV2 ) { liquidityBridge = _liquidityBridge; pegBridge = _pegBridge; pegVault = _pegVault; pegBridgeV2 = _pegBridgeV2; pegVaultV2 = _pegVaultV2; } function initReceiver( address _liquidityBridge, address _pegBridge, address _pegVault, address _pegBridgeV2, address _pegVaultV2 ) internal { require(liquidityBridge == address(0), "liquidityBridge already set"); liquidityBridge = _liquidityBridge; pegBridge = _pegBridge; pegVault = _pegVault; pegBridgeV2 = _pegBridgeV2; pegVaultV2 = _pegVaultV2; } // ============== functions called by executor ============== /** * @notice Execute a message with a successful transfer. * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _transfer The transfer info. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function executeMessageWithTransfer( bytes calldata _message, MsgDataTypes.TransferInfo calldata _transfer, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) public payable { // For message with token transfer, message Id is computed through transfer info // in order to guarantee that each transfer can only be used once. bytes32 messageId = verifyTransfer(_transfer); require(executedMessages[messageId] == MsgDataTypes.TxStatus.Null, "transfer already executed"); executedMessages[messageId] = MsgDataTypes.TxStatus.Pending; bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "MessageWithTransfer")); IBridge(liquidityBridge).verifySigs( abi.encodePacked(domain, messageId, _message, _transfer.srcTxHash), _sigs, _signers, _powers ); MsgDataTypes.TxStatus status; IMessageReceiverApp.ExecutionStatus est = executeMessageWithTransfer(_transfer, _message); if (est == IMessageReceiverApp.ExecutionStatus.Success) { status = MsgDataTypes.TxStatus.Success; } else if (est == IMessageReceiverApp.ExecutionStatus.Retry) { executedMessages[messageId] = MsgDataTypes.TxStatus.Null; emit NeedRetry( MsgDataTypes.MsgType.MessageWithTransfer, messageId, _transfer.srcChainId, _transfer.srcTxHash ); return; } else { est = executeMessageWithTransferFallback(_transfer, _message); if (est == IMessageReceiverApp.ExecutionStatus.Success) { status = MsgDataTypes.TxStatus.Fallback; } else { status = MsgDataTypes.TxStatus.Fail; } } executedMessages[messageId] = status; emitMessageWithTransferExecutedEvent(messageId, status, _transfer); } /** * @notice Execute a message with a refunded transfer. * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _transfer The transfer info. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function executeMessageWithTransferRefund( bytes calldata _message, // the same message associated with the original transfer MsgDataTypes.TransferInfo calldata _transfer, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) public payable { // similar to executeMessageWithTransfer bytes32 messageId = verifyTransfer(_transfer); require(executedMessages[messageId] == MsgDataTypes.TxStatus.Null, "transfer already executed"); executedMessages[messageId] = MsgDataTypes.TxStatus.Pending; bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "MessageWithTransferRefund")); IBridge(liquidityBridge).verifySigs( abi.encodePacked(domain, messageId, _message, _transfer.srcTxHash), _sigs, _signers, _powers ); MsgDataTypes.TxStatus status; IMessageReceiverApp.ExecutionStatus est = executeMessageWithTransferRefund(_transfer, _message); if (est == IMessageReceiverApp.ExecutionStatus.Success) { status = MsgDataTypes.TxStatus.Success; } else if (est == IMessageReceiverApp.ExecutionStatus.Retry) { executedMessages[messageId] = MsgDataTypes.TxStatus.Null; emit NeedRetry( MsgDataTypes.MsgType.MessageWithTransfer, messageId, _transfer.srcChainId, _transfer.srcTxHash ); return; } else { status = MsgDataTypes.TxStatus.Fail; } executedMessages[messageId] = status; emitMessageWithTransferExecutedEvent(messageId, status, _transfer); } /** * @notice Execute a message not associated with a transfer. * @param _message Arbitrary message bytes originated from and encoded by the source app contract * @param _route The info about the sender and the receiver. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by * +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function executeMessage( bytes calldata _message, MsgDataTypes.RouteInfo calldata _route, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external payable { MsgDataTypes.Route memory route = getRouteInfo(_route); executeMessage(_message, route, _sigs, _signers, _powers, "Message"); } // execute message from non-evm chain with bytes for sender address, // otherwise same as above. function executeMessage( bytes calldata _message, MsgDataTypes.RouteInfo2 calldata _route, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external payable { MsgDataTypes.Route memory route = getRouteInfo(_route); executeMessage(_message, route, _sigs, _signers, _powers, "Message2"); } function executeMessage( bytes calldata _message, MsgDataTypes.Route memory _route, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers, string memory domainName ) private { // For message without associated token transfer, message Id is computed through message info, // in order to guarantee that each message can only be applied once bytes32 messageId = computeMessageOnlyId(_route, _message); require(executedMessages[messageId] == MsgDataTypes.TxStatus.Null, "message already executed"); executedMessages[messageId] = MsgDataTypes.TxStatus.Pending; bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), domainName)); IBridge(liquidityBridge).verifySigs(abi.encodePacked(domain, messageId), _sigs, _signers, _powers); MsgDataTypes.TxStatus status; IMessageReceiverApp.ExecutionStatus est = executeMessage(_route, _message); if (est == IMessageReceiverApp.ExecutionStatus.Success) { status = MsgDataTypes.TxStatus.Success; } else if (est == IMessageReceiverApp.ExecutionStatus.Retry) { executedMessages[messageId] = MsgDataTypes.TxStatus.Null; emit NeedRetry(MsgDataTypes.MsgType.MessageOnly, messageId, _route.srcChainId, _route.srcTxHash); return; } else { status = MsgDataTypes.TxStatus.Fail; } executedMessages[messageId] = status; emitMessageOnlyExecutedEvent(messageId, status, _route); } // ================= utils (to avoid stack too deep) ================= function emitMessageWithTransferExecutedEvent( bytes32 _messageId, MsgDataTypes.TxStatus _status, MsgDataTypes.TransferInfo calldata _transfer ) private { emit Executed( MsgDataTypes.MsgType.MessageWithTransfer, _messageId, _status, _transfer.receiver, _transfer.srcChainId, _transfer.srcTxHash ); } function emitMessageOnlyExecutedEvent( bytes32 _messageId, MsgDataTypes.TxStatus _status, MsgDataTypes.Route memory _route ) private { emit Executed( MsgDataTypes.MsgType.MessageOnly, _messageId, _status, _route.receiver, _route.srcChainId, _route.srcTxHash ); } function executeMessageWithTransfer(MsgDataTypes.TransferInfo calldata _transfer, bytes calldata _message) private returns (IMessageReceiverApp.ExecutionStatus) { uint256 gasLeftBeforeExecution = gasleft(); (bool ok, bytes memory res) = address(_transfer.receiver).call{value: msg.value}( abi.encodeWithSelector( IMessageReceiverApp.executeMessageWithTransfer.selector, _transfer.sender, _transfer.token, _transfer.amount, _transfer.srcChainId, _message, msg.sender ) ); if (ok) { return abi.decode((res), (IMessageReceiverApp.ExecutionStatus)); } handleExecutionRevert(gasLeftBeforeExecution, res); return IMessageReceiverApp.ExecutionStatus.Fail; } function executeMessageWithTransferFallback(MsgDataTypes.TransferInfo calldata _transfer, bytes calldata _message) private returns (IMessageReceiverApp.ExecutionStatus) { uint256 gasLeftBeforeExecution = gasleft(); (bool ok, bytes memory res) = address(_transfer.receiver).call{value: msg.value}( abi.encodeWithSelector( IMessageReceiverApp.executeMessageWithTransferFallback.selector, _transfer.sender, _transfer.token, _transfer.amount, _transfer.srcChainId, _message, msg.sender ) ); if (ok) { return abi.decode((res), (IMessageReceiverApp.ExecutionStatus)); } handleExecutionRevert(gasLeftBeforeExecution, res); return IMessageReceiverApp.ExecutionStatus.Fail; } function executeMessageWithTransferRefund(MsgDataTypes.TransferInfo calldata _transfer, bytes calldata _message) private returns (IMessageReceiverApp.ExecutionStatus) { uint256 gasLeftBeforeExecution = gasleft(); (bool ok, bytes memory res) = address(_transfer.receiver).call{value: msg.value}( abi.encodeWithSelector( IMessageReceiverApp.executeMessageWithTransferRefund.selector, _transfer.token, _transfer.amount, _message, msg.sender ) ); if (ok) { return abi.decode((res), (IMessageReceiverApp.ExecutionStatus)); } handleExecutionRevert(gasLeftBeforeExecution, res); return IMessageReceiverApp.ExecutionStatus.Fail; } function verifyTransfer(MsgDataTypes.TransferInfo calldata _transfer) private view returns (bytes32) { bytes32 transferId; address bridgeAddr; MsgDataTypes.TransferType t = _transfer.t; if (t == MsgDataTypes.TransferType.LqRelay) { bridgeAddr = liquidityBridge; transferId = keccak256( abi.encodePacked( _transfer.sender, _transfer.receiver, _transfer.token, _transfer.amount, _transfer.srcChainId, uint64(block.chainid), _transfer.refId ) ); require(IBridge(bridgeAddr).transfers(transferId) == true, "relay not exist"); } else if (t == MsgDataTypes.TransferType.LqWithdraw) { bridgeAddr = liquidityBridge; transferId = keccak256( abi.encodePacked( uint64(block.chainid), _transfer.wdseq, _transfer.receiver, _transfer.token, _transfer.amount ) ); require(IBridge(bridgeAddr).withdraws(transferId) == true, "withdraw not exist"); } else { if (t == MsgDataTypes.TransferType.PegMint || t == MsgDataTypes.TransferType.PegWithdraw) { bridgeAddr = (t == MsgDataTypes.TransferType.PegMint) ? pegBridge : pegVault; transferId = keccak256( abi.encodePacked( _transfer.receiver, _transfer.token, _transfer.amount, _transfer.sender, _transfer.srcChainId, _transfer.refId ) ); } else { bridgeAddr = (t == MsgDataTypes.TransferType.PegV2Mint) ? pegBridgeV2 : pegVaultV2; transferId = keccak256( abi.encodePacked( _transfer.receiver, _transfer.token, _transfer.amount, _transfer.sender, _transfer.srcChainId, _transfer.refId, bridgeAddr ) ); } // function is same for peg, peg2, vault, vault2 require(IPeggedTokenBridge(bridgeAddr).records(transferId) == true, "record not exist"); } require(IDelayedTransfer(bridgeAddr).delayedTransfers(transferId).timestamp == 0, "transfer delayed"); return keccak256(abi.encodePacked(MsgDataTypes.MsgType.MessageWithTransfer, bridgeAddr, transferId)); } function computeMessageOnlyId(MsgDataTypes.Route memory _route, bytes calldata _message) private view returns (bytes32) { bytes memory sender = _route.senderBytes; if (sender.length == 0) { sender = abi.encodePacked(_route.sender); } return keccak256( abi.encodePacked( MsgDataTypes.MsgType.MessageOnly, sender, _route.receiver, _route.srcChainId, _route.srcTxHash, uint64(block.chainid), _message ) ); } function executeMessage(MsgDataTypes.Route memory _route, bytes calldata _message) private returns (IMessageReceiverApp.ExecutionStatus) { uint256 gasLeftBeforeExecution = gasleft(); bool ok; bytes memory res; if (_route.senderBytes.length == 0) { (ok, res) = address(_route.receiver).call{value: msg.value}( abi.encodeWithSelector( bytes4(keccak256(bytes("executeMessage(address,uint64,bytes,address)"))), _route.sender, _route.srcChainId, _message, msg.sender ) ); } else { (ok, res) = address(_route.receiver).call{value: msg.value}( abi.encodeWithSelector( bytes4(keccak256(bytes("executeMessage(bytes,uint64,bytes,address)"))), _route.senderBytes, _route.srcChainId, _message, msg.sender ) ); } if (ok) { return abi.decode((res), (IMessageReceiverApp.ExecutionStatus)); } handleExecutionRevert(gasLeftBeforeExecution, res); return IMessageReceiverApp.ExecutionStatus.Fail; } function handleExecutionRevert(uint256 _gasLeftBeforeExecution, bytes memory _returnData) private { uint256 gasLeftAfterExecution = gasleft(); uint256 maxTargetGasLimit = block.gaslimit - preExecuteMessageGasUsage; if (_gasLeftBeforeExecution < maxTargetGasLimit && gasLeftAfterExecution <= _gasLeftBeforeExecution / 64) { // if this happens, the executor must have not provided sufficient gas limit, // then the tx should revert instead of recording a non-retryable failure status // https://github.com/wolflo/evm-opcodes/blob/main/gas.md#aa-f-gas-to-send-with-call-operations assembly { invalid() } } string memory revertMsg = Utils.getRevertMsg(_returnData); // revert the execution if the revert message has the ABORT prefix checkAbortPrefix(revertMsg); // otherwiase, emit revert message, return and mark the execution as failed (non-retryable) emit CallReverted(revertMsg); } function checkAbortPrefix(string memory _revertMsg) private pure { bytes memory prefixBytes = bytes(MsgDataTypes.ABORT_PREFIX); bytes memory msgBytes = bytes(_revertMsg); if (msgBytes.length >= prefixBytes.length) { for (uint256 i = 0; i < prefixBytes.length; i++) { if (msgBytes[i] != prefixBytes[i]) { return; // prefix not match, return } } revert(_revertMsg); // prefix match, revert } } function getRouteInfo(MsgDataTypes.RouteInfo calldata _route) private pure returns (MsgDataTypes.Route memory) { return MsgDataTypes.Route(_route.sender, "", _route.receiver, _route.srcChainId, _route.srcTxHash); } function getRouteInfo(MsgDataTypes.RouteInfo2 calldata _route) private pure returns (MsgDataTypes.Route memory) { return MsgDataTypes.Route(address(0), _route.sender, _route.receiver, _route.srcChainId, _route.srcTxHash); } // ================= helper functions ===================== /** * @notice combine bridge transfer and msg execution calls into a single tx * @dev caller needs to get the required input params from SGN * @param _tp params to call bridge transfer * @param _mp params to execute message */ function transferAndExecuteMsg( MsgDataTypes.BridgeTransferParams calldata _tp, MsgDataTypes.MsgWithTransferExecutionParams calldata _mp ) external { _bridgeTransfer(_mp.transfer.t, _tp); executeMessageWithTransfer(_mp.message, _mp.transfer, _mp.sigs, _mp.signers, _mp.powers); } /** * @notice combine bridge refund and msg execution calls into a single tx * @dev caller needs to get the required input params from SGN * @param _tp params to call bridge transfer for refund * @param _mp params to execute message for refund */ function refundAndExecuteMsg( MsgDataTypes.BridgeTransferParams calldata _tp, MsgDataTypes.MsgWithTransferExecutionParams calldata _mp ) external { _bridgeTransfer(_mp.transfer.t, _tp); executeMessageWithTransferRefund(_mp.message, _mp.transfer, _mp.sigs, _mp.signers, _mp.powers); } function _bridgeTransfer(MsgDataTypes.TransferType t, MsgDataTypes.BridgeTransferParams calldata _params) private { if (t == MsgDataTypes.TransferType.LqRelay) { IBridge(liquidityBridge).relay(_params.request, _params.sigs, _params.signers, _params.powers); } else if (t == MsgDataTypes.TransferType.LqWithdraw) { IBridge(liquidityBridge).withdraw(_params.request, _params.sigs, _params.signers, _params.powers); } else if (t == MsgDataTypes.TransferType.PegMint) { IPeggedTokenBridge(pegBridge).mint(_params.request, _params.sigs, _params.signers, _params.powers); } else if (t == MsgDataTypes.TransferType.PegV2Mint) { IPeggedTokenBridgeV2(pegBridgeV2).mint(_params.request, _params.sigs, _params.signers, _params.powers); } else if (t == MsgDataTypes.TransferType.PegWithdraw) { IOriginalTokenVault(pegVault).withdraw(_params.request, _params.sigs, _params.signers, _params.powers); } else if (t == MsgDataTypes.TransferType.PegV2Withdraw) { IOriginalTokenVaultV2(pegVaultV2).withdraw(_params.request, _params.sigs, _params.signers, _params.powers); } } // ================= contract config ================= function setLiquidityBridge(address _addr) public onlyOwner { require(_addr != address(0), "invalid address"); liquidityBridge = _addr; emit LiquidityBridgeUpdated(liquidityBridge); } function setPegBridge(address _addr) public onlyOwner { require(_addr != address(0), "invalid address"); pegBridge = _addr; emit PegBridgeUpdated(pegBridge); } function setPegVault(address _addr) public onlyOwner { require(_addr != address(0), "invalid address"); pegVault = _addr; emit PegVaultUpdated(pegVault); } function setPegBridgeV2(address _addr) public onlyOwner { require(_addr != address(0), "invalid address"); pegBridgeV2 = _addr; emit PegBridgeV2Updated(pegBridgeV2); } function setPegVaultV2(address _addr) public onlyOwner { require(_addr != address(0), "invalid address"); pegVaultV2 = _addr; emit PegVaultV2Updated(pegVaultV2); } function setPreExecuteMessageGasUsage(uint256 _usage) public onlyOwner { preExecuteMessageGasUsage = _usage; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.17; import "../../safeguard/Ownable.sol"; import "../../interfaces/ISigsVerifier.sol"; contract MessageBusSender is Ownable { ISigsVerifier public immutable sigsVerifier; uint256 public feeBase; uint256 public feePerByte; mapping(address => uint256) public withdrawnFees; event Message(address indexed sender, address receiver, uint256 dstChainId, bytes message, uint256 fee); // message to non-evm chain with >20 bytes addr event Message2(address indexed sender, bytes receiver, uint256 dstChainId, bytes message, uint256 fee); event MessageWithTransfer( address indexed sender, address receiver, uint256 dstChainId, address bridge, bytes32 srcTransferId, bytes message, uint256 fee ); event FeeWithdrawn(address receiver, uint256 amount); event FeeBaseUpdated(uint256 feeBase); event FeePerByteUpdated(uint256 feePerByte); constructor(ISigsVerifier _sigsVerifier) { sigsVerifier = _sigsVerifier; } /** * @notice Sends a message to a contract on another chain. * Sender needs to make sure the uniqueness of the message Id, which is computed as * hash(type.MessageOnly, sender, receiver, srcChainId, srcTxHash, dstChainId, message). * If messages with the same Id are sent, only one of them will succeed at dst chain. * A fee is charged in the native gas token. * @param _receiver The address of the destination app contract. * @param _dstChainId The destination chain ID. * @param _message Arbitrary message bytes to be decoded by the destination app contract. */ function sendMessage( address _receiver, uint256 _dstChainId, bytes calldata _message ) external payable { _sendMessage(_dstChainId, _message); emit Message(msg.sender, _receiver, _dstChainId, _message, msg.value); } // Send message to non-evm chain with bytes for receiver address, // otherwise same as above. function sendMessage( bytes calldata _receiver, uint256 _dstChainId, bytes calldata _message ) external payable { _sendMessage(_dstChainId, _message); emit Message2(msg.sender, _receiver, _dstChainId, _message, msg.value); } function _sendMessage(uint256 _dstChainId, bytes calldata _message) private { require(_dstChainId != block.chainid, "Invalid chainId"); uint256 minFee = calcFee(_message); require(msg.value >= minFee, "Insufficient fee"); } /** * @notice Sends a message associated with a transfer to a contract on another chain. * If messages with the same srcTransferId are sent, only one of them will succeed. * A fee is charged in the native token. * @param _receiver The address of the destination app contract. * @param _dstChainId The destination chain ID. * @param _srcBridge The bridge contract to send the transfer with. * @param _srcTransferId The transfer ID. * @param _dstChainId The destination chain ID. * @param _message Arbitrary message bytes to be decoded by the destination app contract. */ function sendMessageWithTransfer( address _receiver, uint256 _dstChainId, address _srcBridge, bytes32 _srcTransferId, bytes calldata _message ) external payable { require(_dstChainId != block.chainid, "Invalid chainId"); uint256 minFee = calcFee(_message); require(msg.value >= minFee, "Insufficient fee"); // SGN needs to verify // 1. msg.sender matches sender of the src transfer // 2. dstChainId matches dstChainId of the src transfer // 3. bridge is either liquidity bridge, peg src vault, or peg dst bridge emit MessageWithTransfer(msg.sender, _receiver, _dstChainId, _srcBridge, _srcTransferId, _message, msg.value); } /** * @notice Withdraws message fee in the form of native gas token. * @param _account The address receiving the fee. * @param _cumulativeFee The cumulative fee credited to the account. Tracked by SGN. * @param _sigs The list of signatures sorted by signing addresses in ascending order. A withdrawal must be * signed-off by +2/3 of the sigsVerifier's current signing power to be delivered. * @param _signers The sorted list of signers. * @param _powers The signing powers of the signers. */ function withdrawFee( address _account, uint256 _cumulativeFee, bytes[] calldata _sigs, address[] calldata _signers, uint256[] calldata _powers ) external { bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "withdrawFee")); sigsVerifier.verifySigs(abi.encodePacked(domain, _account, _cumulativeFee), _sigs, _signers, _powers); uint256 amount = _cumulativeFee - withdrawnFees[_account]; require(amount > 0, "No new amount to withdraw"); withdrawnFees[_account] = _cumulativeFee; (bool sent, ) = _account.call{value: amount, gas: 50000}(""); require(sent, "failed to withdraw fee"); emit FeeWithdrawn(_account, amount); } /** * @notice Calculates the required fee for the message. * @param _message Arbitrary message bytes to be decoded by the destination app contract. @ @return The required fee. */ function calcFee(bytes calldata _message) public view returns (uint256) { return feeBase + _message.length * feePerByte; } // -------------------- Admin -------------------- function setFeePerByte(uint256 _fee) external onlyOwner { feePerByte = _fee; emit FeePerByteUpdated(feePerByte); } function setFeeBase(uint256 _fee) external onlyOwner { feeBase = _fee; emit FeeBaseUpdated(feeBase); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. * * This adds a normal func that setOwner if _owner is address(0). So we can't allow * renounceOwnership. So we can support Proxy based upgradable contract */ abstract contract Ownable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _setOwner(msg.sender); } /** * @dev Only to be called by inherit contracts, in their init func called by Proxy * we require _owner == address(0), which is only possible when it's a delegateCall * because constructor sets _owner in contract state. */ function initOwner() internal { require(_owner == address(0), "owner already set"); _setOwner(msg.sender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == msg.sender, "Ownable: caller is not the owner"); _; } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; interface IMultichainEndpoint { enum CallbackExecutionStatus { Success, Failed, Retry } function executeMessageWithTransfer( address _token, uint256 _amount, uint64 srcChainId, bytes memory _message ) external payable returns (CallbackExecutionStatus); function executeMessageWithTransferFallback( address _token, uint256 _amount, bytes calldata _message ) external payable returns (CallbackExecutionStatus); }
{ "optimizer": { "enabled": true, "runs": 300 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_messageBus","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"prev","type":"address"},{"indexed":false,"internalType":"address","name":"updated","type":"address"}],"name":"ActualEndpointChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"reason","type":"bytes"}],"name":"EndpointExecutionReverted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"bool","name":"isSet","type":"bool"}],"name":"SetAuthorisedSender","type":"event"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"allowedSenderSetup","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint64","name":"","type":"uint64"}],"name":"allowedSenders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"burnAndUnlock","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint64","name":"","type":"uint64"}],"name":"crossChainAssetsData","outputs":[{"internalType":"bool","name":"isDataSet","type":"bool"},{"internalType":"address","name":"token","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint64","name":"chainId","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract IMultichainEndpoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_sender","type":"bytes"},{"internalType":"uint64","name":"_srcChainId","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"}],"name":"executeMessage","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"srcContract","type":"address"},{"internalType":"uint64","name":"_srcChainId","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"","type":"address"}],"name":"executeMessage","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint64","name":"_srcChainId","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"}],"name":"executeMessageWithTransfer","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint64","name":"_srcChainId","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"}],"name":"executeMessageWithTransferFallback","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"}],"name":"executeMessageWithTransferRefund","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"lockAndMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"messageBus","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"address","name":"","type":"address"}],"name":"mintedTokenByOriginal","outputs":[{"internalType":"contract CrossChainERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"contract CrossChainERC20","name":"","type":"address"}],"name":"originalTokenByMinted","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_endpoint","type":"address"}],"name":"setActualEndpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint64","name":"srcChainId","type":"uint64"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"internalType":"struct CrossChainVaultApp.SetAllowedSender[]","name":"senders","type":"tuple[]"}],"name":"setAllowedSenders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isDataSet","type":"bool"},{"internalType":"address","name":"token","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint64","name":"chainId","type":"uint64"}],"internalType":"struct CrossChainVaultApp.CrossChainAssetData[]","name":"assets","type":"tuple[]"}],"name":"setCrossChainAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract ICrossChainVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a06040523480156200001157600080fd5b5060405162003aa138038062003aa18339810160408190526200003491620000dc565b600080546001600160a01b0319166001600160a01b0383161790556200005a336200006d565b506001600160a01b031660805262000114565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b0381168114620000d757600080fd5b919050565b60008060408385031215620000f057600080fd5b620000fb83620000bf565b91506200010b60208401620000bf565b90509250929050565b60805161395c620001456000396000818161042401528181611355015281816113a10152611919015261395c6000f3fe6080604052600436106200013b5760003560e01c80637d25bc2811620000ad578063aadc047d116200006c578063aadc047d1462000384578063aaf477d114620003d4578063f2fde38b14620003eb578063fbfa77cf1462000410578063fe2834e9146200044657600080fd5b80637d25bc2814620002cd5780638da5cb5b14620003065780638f1c436c14620003265780639c649fdf146200034b578063a1a227fa146200036257600080fd5b80635ab7afc611620000fa5780635ab7afc614620001f15780635e280f11146200020857806363556ec114620002435780637b13126414620002885780637cd2bffc14620001f157600080fd5b8063063ce4e514620001485780630bcb498214620001775780632c2b1ec6146200018e5780634e83c45614620001b55780635a7d702d14620001cc57600080fd5b366200014357005b600080fd5b6200015f6200015936600462001f7e565b6200047a565b6040516200016e919062002035565b60405180910390f35b6200015f620001883660046200205e565b620004e1565b3480156200019b57600080fd5b50620001b3620001ad366004620020d9565b62000543565b005b620001b3620001c6366004620021fc565b6200088a565b348015620001d957600080fd5b50620001b3620001eb36600462002284565b62000b32565b6200015f62000202366004620022ab565b62000c6d565b3480156200021557600080fd5b506002546200022a906001600160a01b031681565b6040516001600160a01b0390911681526020016200016e565b3480156200025057600080fd5b506200022a620002623660046200234f565b60036020908152600092835260408084209091529082529020546001600160a01b031681565b3480156200029557600080fd5b506200022a620002a73660046200234f565b60046020908152600092835260408084209091529082529020546001600160a01b031681565b348015620002da57600080fd5b50620002f2620002ec3660046200238d565b62000cd1565b6040516200016e9695949392919062002414565b3480156200031357600080fd5b506001546001600160a01b03166200022a565b3480156200033357600080fd5b50620001b3620003453660046200247a565b62000e4d565b6200015f6200035c366004620024e1565b62000fc9565b3480156200036f57600080fd5b506000546200022a906001600160a01b031681565b3480156200039157600080fd5b50620003c3620003a33660046200238d565b600560209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016200016e565b620001b3620003e5366004620021fc565b620012df565b348015620003f857600080fd5b50620001b36200040a36600462002284565b620014b2565b3480156200041d57600080fd5b506200022a7f000000000000000000000000000000000000000000000000000000000000000081565b3480156200045357600080fd5b50620003c36200046536600462002535565b60066020526000908152604090205460ff1681565b600080546001600160a01b03163314620004d75760405162461bcd60e51b815260206004820152601960248201527863616c6c6572206973206e6f74206d6573736167652062757360381b60448201526064015b60405180910390fd5b9695505050505050565b600080546001600160a01b031633146200053a5760405162461bcd60e51b815260206004820152601960248201527863616c6c6572206973206e6f74206d6573736167652062757360381b6044820152606401620004ce565b95945050505050565b33620005576001546001600160a01b031690565b6001600160a01b031614620005af5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620004ce565b60005b81811015620008855760066000848484818110620005d457620005d462002555565b9050606002016020016020810190620005ee919062002535565b6001600160401b0316815260208101919091526040016000205460ff16156200065a5760405162461bcd60e51b815260206004820152601760248201527f53656e64657220697320616c72656164792073657475700000000000000000006044820152606401620004ce565b8282828181106200066f576200066f62002555565b905060600201602001602081019062000689919062002535565b6001600160401b0316838383818110620006a757620006a762002555565b620006bf926020606090920201908101915062002284565b6001600160a01b03167f6d5222c451f4b8e6a30bc69e4f6f13dc69c8ce27d4c06d4314cba786a8adae48858585818110620006fe57620006fe62002555565b90506060020160400160208101906200071891906200257a565b604051901515815260200160405180910390a382828281811062000740576200074062002555565b90506060020160400160208101906200075a91906200257a565b6005600085858581811062000773576200077362002555565b6200078b926020606090920201908101915062002284565b6001600160a01b03166001600160a01b031681526020019081526020016000206000858585818110620007c257620007c262002555565b9050606002016020016020810190620007dc919062002535565b6001600160401b03166001600160401b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600660008585858181106200082e576200082e62002555565b905060600201602001602081019062000848919062002535565b6001600160401b031681526020810191909152604001600020805460ff1916911515919091179055806200087c81620025b0565b915050620005b2565b505050565b6002546001600160a01b03163314620008d95760405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a5908195b991c1bda5b9d60821b6044820152606401620004ce565b6001600160401b03841660009081526004602090815260408083206001600160a01b03878116855292529091205416620009565760405162461bcd60e51b815260206004820152601960248201527f496e76616c69642063726f73732d636861696e20746f6b656e000000000000006044820152606401620004ce565b6200096d6001600160a01b03841633308562001593565b604051632770a7eb60e21b81523060048201526024810183905283906001600160a01b03821690639dc29fac90604401600060405180830381600087803b158015620009b857600080fd5b505af1158015620009cd573d6000803e3d6000fd5b506000925060019150620009de9050565b826001600160a01b031663cab416b46040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000a1d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a439190620025cc565b6040805160ff90931660208401526001600160a01b03909116908201526060810185905260800160405160208183030381529060405290506000818460405160200162000a92929190620025ec565b60408051601f198184030181529082905260005463299aee5160e11b835290925062000b28918a918a9185916001600160a01b031690635335dca29062000ade90849060040162002615565b602060405180830381865afa15801562000afc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000b2291906200262a565b62001606565b5050505050505050565b3362000b466001546001600160a01b031690565b6001600160a01b03161462000b9e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620004ce565b6002546001600160a01b03161562000c045760405162461bcd60e51b815260206004820152602260248201527f54686520656e64706f696e7420697320616c726561647920636f6e6669677572604482015261195960f21b6064820152608401620004ce565b600254604080516001600160a01b03928316815291831660208301527fce9f9cf829dff23cd2adc270f92fa00964c95ee6627c10fbf00da1a18bd85dc9910160405180910390a1600280546001600160a01b0319166001600160a01b0392909216919091179055565b600080546001600160a01b0316331462000cc65760405162461bcd60e51b815260206004820152601960248201527863616c6c6572206973206e6f74206d6573736167652062757360381b6044820152606401620004ce565b979650505050505050565b60076020908152600092835260408084209091529082529020805460018201805460ff8316936101009093046001600160a01b031692919062000d149062002644565b80601f016020809104026020016040519081016040528092919081815260200182805462000d429062002644565b801562000d935780601f1062000d675761010080835404028352916020019162000d93565b820191906000526020600020905b81548152906001019060200180831162000d7557829003601f168201915b50505050509080600201805462000daa9062002644565b80601f016020809104026020016040519081016040528092919081815260200182805462000dd89062002644565b801562000e295780601f1062000dfd5761010080835404028352916020019162000e29565b820191906000526020600020905b81548152906001019060200180831162000e0b57829003601f168201915b5050506003909301549192505060ff8116906001600160401b036101009091041686565b3362000e616001546001600160a01b031690565b6001600160a01b03161462000eb95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620004ce565b60005b81811015620008855782828281811062000eda5762000eda62002555565b905060200281019062000eee919062002680565b6007600085858581811062000f075762000f0762002555565b905060200281019062000f1b919062002680565b62000f2e90604081019060200162002284565b6001600160a01b03166001600160a01b03168152602001908152602001600020600085858581811062000f655762000f6562002555565b905060200281019062000f79919062002680565b62000f8c9060c081019060a00162002535565b6001600160401b03168152602081019190915260400160002062000fb1828262002837565b5081905062000fc081620025b0565b91505062000ebc565b600080546001600160a01b03163314620010225760405162461bcd60e51b815260206004820152601960248201527863616c6c6572206973206e6f74206d6573736167652062757360381b6044820152606401620004ce565b6001600160a01b03861660009081526005602090815260408083206001600160401b038916845290915290205460ff16620010965760405162461bcd60e51b81526020600482015260136024820152722ab730baba3437b934b9b2b21039b2b73232b960691b6044820152606401620004ce565b600080620010a78587018762002939565b91509150600080620010ba898562001624565b6002549193509150620010db906001600160a01b0380851691168362001986565b600254604051637c5141fb60e01b81526001916001600160a01b031690637c5141fb906200111490869086908f908a90600401620029a3565b6020604051808303816000875af192505050801562001152575060408051601f3d908101601f191682019092526200114f91810190620029dc565b60015b62001247573d80801562001183576040519150601f19603f3d011682016040523d82523d6000602084013e62001188565b606091505b507fbd8deeebc4a2cd5e7ce108bacfdd51d6864f4e701d33245727f3ce6a9a25c19781604051620011ba919062002615565b60405180910390a160025460405163bc886f6560e01b81526001600160a01b039091169063bc886f6590620011f890879087908a90600401620029ff565b6020604051808303816000875af115801562001218573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200123e9190620029dc565b9150506200124a565b90505b60008160028111156200126157620012616200201f565b0362001276576001955050505050506200053a565b60018160028111156200128d576200128d6200201f565b03620012a2576000955050505050506200053a565b6002816002811115620012b957620012b96200201f565b03620012ce576002955050505050506200053a565b5060009a9950505050505050505050565b6002546001600160a01b031633146200132e5760405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a5908195b991c1bda5b9d60821b6044820152606401620004ce565b620013456001600160a01b03841633308562001593565b6200137b6001600160a01b0384167f000000000000000000000000000000000000000000000000000000000000000084620019b8565b60405163282d3fdf60e01b81526001600160a01b038481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063282d3fdf906044016020604051808303816000875af1158015620013eb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200141191906200262a565b604080516000602082018190526001600160a01b03871682840152606080830185905283518084039091018152608083019093529294509091906200145d908390859060a001620025ec565b60408051601f198184030181529082905260005463299aee5160e11b8352909250620014a9918991899185916001600160a01b031690635335dca29062000ade90849060040162002615565b50505050505050565b33620014c66001546001600160a01b031690565b6001600160a01b0316146200151e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620004ce565b6001600160a01b038116620015855760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401620004ce565b620015908162001a6c565b50565b6040516001600160a01b0380851660248301528316604482015260648101829052620016009085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915262001abe565b50505050565b60005462001600908590859085906001600160a01b03168562001b9a565b60008060008060008580602001905181019062001642919062002a29565b92509250925060008360ff1660018111156200166257620016626200201f565b9194508491905060008160018111156200168057620016806200201f565b03620018d6576001600160a01b0380841660009081526007602090815260408083206001600160401b038d1684528252808320815160c081018352815460ff81161515825261010090049095169285019290925260018201805493949391840191620016ec9062002644565b80601f01602080910402602001604051908101604052809291908181526020018280546200171a9062002644565b80156200176b5780601f106200173f576101008083540402835291602001916200176b565b820191906000526020600020905b8154815290600101906020018083116200174d57829003601f168201915b50505050508152602001600282018054620017869062002644565b80601f0160208091040260200160405190810160405280929190818152602001828054620017b49062002644565b8015620018055780601f10620017d95761010080835404028352916020019162001805565b820191906000526020600020905b815481529060010190602001808311620017e757829003601f168201915b50505091835250506003919091015460ff8116602083015261010090046001600160401b031660409091015280519091506200187a5760405162461bcd60e51b815260206004820152601360248201527213595d1859185d18481a5cc81b9bdd081cd95d606a1b6044820152606401620004ce565b620018cd6040518060a001604052808360400151815260200183606001518152602001836080015160ff1681526020018b6001600160401b03168152602001866001600160a01b03168152508462001c09565b9650506200197b565b6001816001811115620018ed57620018ed6200201f565b036200014357604051637eee288d60e01b81526001600160a01b038481166004830152602482018490527f00000000000000000000000000000000000000000000000000000000000000001690637eee288d90604401600060405180830381600087803b1580156200195e57600080fd5b505af115801562001973573d6000803e3d6000fd5b505050508295505b505050509250929050565b6040516001600160a01b0383166024820152604481018290526200088590849063a9059cbb60e01b90606401620015c8565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa15801562001a09573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001a2f91906200262a565b9050620016008463095ea7b360e01b8562001a4b868662002a71565b6040516001600160a01b0390921660248301526044820152606401620015c8565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600062001b15826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031662001d679092919063ffffffff16565b905080516000148062001b3957508080602001905181019062001b39919062002a87565b620008855760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401620004ce565b604051634f9e72ad60e11b81526001600160a01b03831690639f3ce55a90839062001bce9089908990899060040162002aa7565b6000604051808303818588803b15801562001be857600080fd5b505af115801562001bfd573d6000803e3d6000fd5b50505050505050505050565b60608201516001600160401b0316600090815260036020908152604080832060808601516001600160a01b0390811685529252822054168062001cfb578360405162001c559062001ef9565b62001c61919062002ada565b604051809103906000f08015801562001c7e573d6000803e3d6000fd5b506060850180516001600160401b03908116600090815260036020908152604080832060808b0180516001600160a01b03908116865291845282852080546001600160a01b03199081168a851690811790925591519751909616855260048452828520958552949092529091208054909216921691909117905590505b6040516340c10f1960e01b8152306004820152602481018490526001600160a01b038216906340c10f1990604401600060405180830381600087803b15801562001d4457600080fd5b505af115801562001d59573d6000803e3d6000fd5b509293505050505b92915050565b606062001d78848460008562001d80565b949350505050565b60608247101562001de35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401620004ce565b600080866001600160a01b0316858760405162001e01919062002b57565b60006040518083038185875af1925050503d806000811462001e40576040519150601f19603f3d011682016040523d82523d6000602084013e62001e45565b606091505b509150915062000cc6878383876060831562001ec657825160000362001ebe576001600160a01b0385163b62001ebe5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620004ce565b508162001d78565b62001d78838381511562001edd5781518083602001fd5b8060405162461bcd60e51b8152600401620004ce919062002615565b610dbb8062002b6c83390190565b60008083601f84011262001f1a57600080fd5b5081356001600160401b0381111562001f3257600080fd5b60208301915083602082850101111562001f4b57600080fd5b9250929050565b6001600160401b03811681146200159057600080fd5b6001600160a01b03811681146200159057600080fd5b6000806000806000806080878903121562001f9857600080fd5b86356001600160401b038082111562001fb057600080fd5b62001fbe8a838b0162001f07565b90985096506020890135915062001fd58262001f52565b9094506040880135908082111562001fec57600080fd5b5062001ffb89828a0162001f07565b9094509250506060870135620020118162001f68565b809150509295509295509295565b634e487b7160e01b600052602160045260246000fd5b60208101600383106200205857634e487b7160e01b600052602160045260246000fd5b91905290565b6000806000806000608086880312156200207757600080fd5b8535620020848162001f68565b94506020860135935060408601356001600160401b03811115620020a757600080fd5b620020b58882890162001f07565b9094509250506060860135620020cb8162001f68565b809150509295509295909350565b60008060208385031215620020ed57600080fd5b82356001600160401b03808211156200210557600080fd5b818501915085601f8301126200211a57600080fd5b8135818111156200212a57600080fd5b8660206060830285010111156200214057600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200217a57600080fd5b81356001600160401b038082111562002197576200219762002152565b604051601f8301601f19908116603f01168101908282118183101715620021c257620021c262002152565b81604052838152866020858801011115620021dc57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156200221557600080fd5b8535620022228162001f68565b94506020860135620022348162001f52565b93506040860135620022468162001f68565b92506060860135915060808601356001600160401b038111156200226957600080fd5b620022778882890162002168565b9150509295509295909350565b6000602082840312156200229757600080fd5b8135620022a48162001f68565b9392505050565b600080600080600080600060c0888a031215620022c757600080fd5b8735620022d48162001f68565b96506020880135620022e68162001f68565b9550604088013594506060880135620022ff8162001f52565b935060808801356001600160401b038111156200231b57600080fd5b620023298a828b0162001f07565b90945092505060a08801356200233f8162001f68565b8091505092959891949750929550565b600080604083850312156200236357600080fd5b8235620023708162001f52565b91506020830135620023828162001f68565b809150509250929050565b60008060408385031215620023a157600080fd5b8235620023ae8162001f68565b91506020830135620023828162001f52565b60005b83811015620023dd578181015183820152602001620023c3565b50506000910152565b6000815180845262002400816020860160208601620023c0565b601f01601f19169290920160200192915050565b86151581526001600160a01b038616602082015260c0604082015260006200244060c0830187620023e6565b8281036060840152620024548187620023e6565b91505060ff841660808301526001600160401b03831660a0830152979650505050505050565b600080602083850312156200248e57600080fd5b82356001600160401b0380821115620024a657600080fd5b818501915085601f830112620024bb57600080fd5b813581811115620024cb57600080fd5b8660208260051b85010111156200214057600080fd5b600080600080600060808688031215620024fa57600080fd5b8535620025078162001f68565b94506020860135620025198162001f52565b935060408601356001600160401b03811115620020a757600080fd5b6000602082840312156200254857600080fd5b8135620022a48162001f52565b634e487b7160e01b600052603260045260246000fd5b80151581146200159057600080fd5b6000602082840312156200258d57600080fd5b8135620022a4816200256b565b634e487b7160e01b600052601160045260246000fd5b600060018201620025c557620025c56200259a565b5060010190565b600060208284031215620025df57600080fd5b8151620022a48162001f68565b604081526000620026016040830185620023e6565b82810360208401526200053a8185620023e6565b602081526000620022a46020830184620023e6565b6000602082840312156200263d57600080fd5b5051919050565b600181811c908216806200265957607f821691505b6020821081036200267a57634e487b7160e01b600052602260045260246000fd5b50919050565b6000823560be198336030181126200269757600080fd5b9190910192915050565b6000808335601e19843603018112620026b957600080fd5b8301803591506001600160401b03821115620026d457600080fd5b60200191503681900382131562001f4b57600080fd5b601f8211156200088557600081815260208120601f850160051c81016020861015620027135750805b601f850160051c820191505b8181101562002734578281556001016200271f565b505050505050565b6001600160401b0383111562002756576200275662002152565b6200276e8362002767835462002644565b83620026ea565b6000601f841160018114620027a557600085156200278c5750838201355b600019600387901b1c1916600186901b17835562002802565b600083815260209020601f19861690835b82811015620027d85786850135825560209485019460019092019101620027b6565b5086821015620027f65760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60ff811681146200159057600080fd5b6000813562001d618162002809565b6000813562001d618162001f52565b813562002844816200256b565b815460ff19811691151560ff1691821783556020840135620028668162001f68565b74ffffffffffffffffffffffffffffffffffffffff008160081b16836affffffffffffffffffffff60a81b841617178455505050620028a96040830183620026a1565b620028b98183600186016200273c565b5050620028ca6060830183620026a1565b620028da8183600286016200273c565b50506003810162002903620028f26080850162002819565b825460ff191660ff91909116178255565b620008856200291560a0850162002828565b825468ffffffffffffffff00191660089190911b68ffffffffffffffff0016178255565b600080604083850312156200294d57600080fd5b82356001600160401b03808211156200296557600080fd5b620029738683870162002168565b935060208501359150808211156200298a57600080fd5b50620029998582860162002168565b9150509250929050565b6001600160a01b03851681528360208201526001600160401b0383166040820152608060608201526000620004d76080830184620023e6565b600060208284031215620029ef57600080fd5b815160038110620022a457600080fd5b6001600160a01b03841681528260208201526060604082015260006200053a6060830184620023e6565b60008060006060848603121562002a3f57600080fd5b835162002a4c8162002809565b602085015190935062002a5f8162001f68565b80925050604084015190509250925092565b8082018082111562001d615762001d616200259a565b60006020828403121562002a9a57600080fd5b8151620022a4816200256b565b6001600160a01b03841681526001600160401b03831660208201526060604082015260006200053a6060830184620023e6565b602081526000825160a0602084015262002af860c0840182620023e6565b90506020840151601f1984830301604085015262002b178282620023e6565b91505060ff60408501511660608401526001600160401b0360608501511660808401526001600160a01b0360808501511660a08401528091505092915050565b6000825162002697818460208701620023c056fe60a06040523480156200001157600080fd5b5060405162000dbb38038062000dbb8339810160408190526200003491620001fc565b805160029062000045908262000369565b5060208101516003906200005a908262000369565b5060408101516004805460608401516080948501516001600160a01b031661010002610100600160a81b03196001600160401b03909216600160a81b0260ff600160a81b03600160e81b031990931660ff90951694909417919091171691909117905533905262000435565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b0381118282101715620001015762000101620000c6565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620001325762000132620000c6565b604052919050565b600082601f8301126200014c57600080fd5b81516001600160401b03811115620001685762000168620000c6565b60206200017e601f8301601f1916820162000107565b82815285828487010111156200019357600080fd5b60005b83811015620001b357858101830151828201840152820162000196565b506000928101909101919091529392505050565b80516001600160401b0381168114620001df57600080fd5b919050565b80516001600160a01b0381168114620001df57600080fd5b6000602082840312156200020f57600080fd5b81516001600160401b03808211156200022757600080fd5b9083019060a082860312156200023c57600080fd5b62000246620000dc565b8251828111156200025657600080fd5b62000264878286016200013a565b8252506020830151828111156200027a57600080fd5b62000288878286016200013a565b6020830152506040830151915060ff82168214620002a557600080fd5b816040820152620002b960608401620001c7565b6060820152620002cc60808401620001e4565b608082015295945050505050565b600181811c90821680620002ef57607f821691505b6020821081036200031057634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200036457600081815260208120601f850160051c810160208610156200033f5750805b601f850160051c820191505b8181101562000360578281556001016200034b565b5050505b505050565b81516001600160401b03811115620003855762000385620000c6565b6200039d81620003968454620002da565b8462000316565b602080601f831160018114620003d55760008415620003bc5750858301515b600019600386901b1c1916600185901b17855562000360565b600085815260208120601f198616915b828110156200040657888601518255948401946001909101908401620003e5565b5085821015620004255787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805161095c6200045f6000396000818161024e01528181610380015261040c015261095c6000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c806370a082311161008c578063a9059cbb11610066578063a9059cbb14610206578063cab416b414610219578063d5f3948814610249578063dd62ed3e1461027057600080fd5b806370a08231146101c257806395d89b41146101eb5780639dc29fac146101f357600080fd5b806318160ddd116100c857806318160ddd1461016457806323b872dd1461017b578063313ce5671461018e57806340c10f19146101ad57600080fd5b806306fdde03146100ef578063095ea7b31461010d5780630d788c3614610130575b600080fd5b6100f76102a9565b604051610104919061078b565b60405180910390f35b61012061011b3660046107f5565b610337565b6040519015158152602001610104565b60045461014b90600160a81b900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610104565b61016d60055481565b604051908152602001610104565b61012061018936600461081f565b610351565b60045461019b9060ff1681565b60405160ff9091168152602001610104565b6101c06101bb3660046107f5565b610375565b005b61016d6101d036600461085b565b6001600160a01b031660009081526020819052604090205490565b6100f76103f4565b6101c06102013660046107f5565b610401565b6101206102143660046107f5565b610477565b6004546102319061010090046001600160a01b031681565b6040516001600160a01b039091168152602001610104565b6102317f000000000000000000000000000000000000000000000000000000000000000081565b61016d61027e36600461087d565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600280546102b6906108b0565b80601f01602080910402602001604051908101604052809291908181526020018280546102e2906108b0565b801561032f5780601f106103045761010080835404028352916020019161032f565b820191906000526020600020905b81548152906001019060200180831161031257829003601f168201915b505050505081565b600033610345818585610485565b60019150505b92915050565b60003361035f858285610579565b61036a85858561060b565b506001949350505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103aa57600080fd5b6001600160a01b038216600090815260208190526040812080548392906103d2908490610900565b9250508190555080600560008282546103eb9190610900565b90915550505050565b600380546102b6906108b0565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461043657600080fd5b6001600160a01b0382166000908152602081905260408120805483929061045e908490610913565b9250508190555080600560008282546103eb9190610913565b60003361034581858561060b565b6001600160a01b0383166104ec5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084015b60405180910390fd5b6001600160a01b03821661054d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016104e3565b6001600160a01b0392831660009081526001602090815260408083209490951682529290925291902055565b6001600160a01b03808416600090815260016020908152604080832093861683529290522054600019811461060557818110156105f85760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016104e3565b6106058484848403610485565b50505050565b6001600160a01b03831661066f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016104e3565b6001600160a01b0382166106d15760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016104e3565b6001600160a01b038316600090815260208190526040902054818110156107495760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016104e3565b6001600160a01b03808516600090815260208190526040808220858503905591851681529081208054849290610780908490610900565b909155505050505050565b600060208083528351808285015260005b818110156107b85785810183015185820160400152820161079c565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146107f057600080fd5b919050565b6000806040838503121561080857600080fd5b610811836107d9565b946020939093013593505050565b60008060006060848603121561083457600080fd5b61083d846107d9565b925061084b602085016107d9565b9150604084013590509250925092565b60006020828403121561086d57600080fd5b610876826107d9565b9392505050565b6000806040838503121561089057600080fd5b610899836107d9565b91506108a7602084016107d9565b90509250929050565b600181811c908216806108c457607f821691505b6020821081036108e457634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561034b5761034b6108ea565b8181038181111561034b5761034b6108ea56fea264697066735822122050795a9fe2ce243c123c04c8b3be3238c0fb1cbccef0c4e17160e0ba4c91412264736f6c63430008110033a2646970667358221220bee0e1b211ad5c40f9a713679b90399aa9363b048369a5226b67a8b3193dec0364736f6c63430008110033000000000000000000000000ee6c6d360216f270bf9dacf85bed79c772cb9f4c0000000000000000000000004066d196a423b2b3b8b054f4f40efb47a74e200c
Deployed Bytecode
0x6080604052600436106200013b5760003560e01c80637d25bc2811620000ad578063aadc047d116200006c578063aadc047d1462000384578063aaf477d114620003d4578063f2fde38b14620003eb578063fbfa77cf1462000410578063fe2834e9146200044657600080fd5b80637d25bc2814620002cd5780638da5cb5b14620003065780638f1c436c14620003265780639c649fdf146200034b578063a1a227fa146200036257600080fd5b80635ab7afc611620000fa5780635ab7afc614620001f15780635e280f11146200020857806363556ec114620002435780637b13126414620002885780637cd2bffc14620001f157600080fd5b8063063ce4e514620001485780630bcb498214620001775780632c2b1ec6146200018e5780634e83c45614620001b55780635a7d702d14620001cc57600080fd5b366200014357005b600080fd5b6200015f6200015936600462001f7e565b6200047a565b6040516200016e919062002035565b60405180910390f35b6200015f620001883660046200205e565b620004e1565b3480156200019b57600080fd5b50620001b3620001ad366004620020d9565b62000543565b005b620001b3620001c6366004620021fc565b6200088a565b348015620001d957600080fd5b50620001b3620001eb36600462002284565b62000b32565b6200015f62000202366004620022ab565b62000c6d565b3480156200021557600080fd5b506002546200022a906001600160a01b031681565b6040516001600160a01b0390911681526020016200016e565b3480156200025057600080fd5b506200022a620002623660046200234f565b60036020908152600092835260408084209091529082529020546001600160a01b031681565b3480156200029557600080fd5b506200022a620002a73660046200234f565b60046020908152600092835260408084209091529082529020546001600160a01b031681565b348015620002da57600080fd5b50620002f2620002ec3660046200238d565b62000cd1565b6040516200016e9695949392919062002414565b3480156200031357600080fd5b506001546001600160a01b03166200022a565b3480156200033357600080fd5b50620001b3620003453660046200247a565b62000e4d565b6200015f6200035c366004620024e1565b62000fc9565b3480156200036f57600080fd5b506000546200022a906001600160a01b031681565b3480156200039157600080fd5b50620003c3620003a33660046200238d565b600560209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016200016e565b620001b3620003e5366004620021fc565b620012df565b348015620003f857600080fd5b50620001b36200040a36600462002284565b620014b2565b3480156200041d57600080fd5b506200022a7f000000000000000000000000ee6c6d360216f270bf9dacf85bed79c772cb9f4c81565b3480156200045357600080fd5b50620003c36200046536600462002535565b60066020526000908152604090205460ff1681565b600080546001600160a01b03163314620004d75760405162461bcd60e51b815260206004820152601960248201527863616c6c6572206973206e6f74206d6573736167652062757360381b60448201526064015b60405180910390fd5b9695505050505050565b600080546001600160a01b031633146200053a5760405162461bcd60e51b815260206004820152601960248201527863616c6c6572206973206e6f74206d6573736167652062757360381b6044820152606401620004ce565b95945050505050565b33620005576001546001600160a01b031690565b6001600160a01b031614620005af5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620004ce565b60005b81811015620008855760066000848484818110620005d457620005d462002555565b9050606002016020016020810190620005ee919062002535565b6001600160401b0316815260208101919091526040016000205460ff16156200065a5760405162461bcd60e51b815260206004820152601760248201527f53656e64657220697320616c72656164792073657475700000000000000000006044820152606401620004ce565b8282828181106200066f576200066f62002555565b905060600201602001602081019062000689919062002535565b6001600160401b0316838383818110620006a757620006a762002555565b620006bf926020606090920201908101915062002284565b6001600160a01b03167f6d5222c451f4b8e6a30bc69e4f6f13dc69c8ce27d4c06d4314cba786a8adae48858585818110620006fe57620006fe62002555565b90506060020160400160208101906200071891906200257a565b604051901515815260200160405180910390a382828281811062000740576200074062002555565b90506060020160400160208101906200075a91906200257a565b6005600085858581811062000773576200077362002555565b6200078b926020606090920201908101915062002284565b6001600160a01b03166001600160a01b031681526020019081526020016000206000858585818110620007c257620007c262002555565b9050606002016020016020810190620007dc919062002535565b6001600160401b03166001600160401b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055506001600660008585858181106200082e576200082e62002555565b905060600201602001602081019062000848919062002535565b6001600160401b031681526020810191909152604001600020805460ff1916911515919091179055806200087c81620025b0565b915050620005b2565b505050565b6002546001600160a01b03163314620008d95760405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a5908195b991c1bda5b9d60821b6044820152606401620004ce565b6001600160401b03841660009081526004602090815260408083206001600160a01b03878116855292529091205416620009565760405162461bcd60e51b815260206004820152601960248201527f496e76616c69642063726f73732d636861696e20746f6b656e000000000000006044820152606401620004ce565b6200096d6001600160a01b03841633308562001593565b604051632770a7eb60e21b81523060048201526024810183905283906001600160a01b03821690639dc29fac90604401600060405180830381600087803b158015620009b857600080fd5b505af1158015620009cd573d6000803e3d6000fd5b506000925060019150620009de9050565b826001600160a01b031663cab416b46040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000a1d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a439190620025cc565b6040805160ff90931660208401526001600160a01b03909116908201526060810185905260800160405160208183030381529060405290506000818460405160200162000a92929190620025ec565b60408051601f198184030181529082905260005463299aee5160e11b835290925062000b28918a918a9185916001600160a01b031690635335dca29062000ade90849060040162002615565b602060405180830381865afa15801562000afc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000b2291906200262a565b62001606565b5050505050505050565b3362000b466001546001600160a01b031690565b6001600160a01b03161462000b9e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620004ce565b6002546001600160a01b03161562000c045760405162461bcd60e51b815260206004820152602260248201527f54686520656e64706f696e7420697320616c726561647920636f6e6669677572604482015261195960f21b6064820152608401620004ce565b600254604080516001600160a01b03928316815291831660208301527fce9f9cf829dff23cd2adc270f92fa00964c95ee6627c10fbf00da1a18bd85dc9910160405180910390a1600280546001600160a01b0319166001600160a01b0392909216919091179055565b600080546001600160a01b0316331462000cc65760405162461bcd60e51b815260206004820152601960248201527863616c6c6572206973206e6f74206d6573736167652062757360381b6044820152606401620004ce565b979650505050505050565b60076020908152600092835260408084209091529082529020805460018201805460ff8316936101009093046001600160a01b031692919062000d149062002644565b80601f016020809104026020016040519081016040528092919081815260200182805462000d429062002644565b801562000d935780601f1062000d675761010080835404028352916020019162000d93565b820191906000526020600020905b81548152906001019060200180831162000d7557829003601f168201915b50505050509080600201805462000daa9062002644565b80601f016020809104026020016040519081016040528092919081815260200182805462000dd89062002644565b801562000e295780601f1062000dfd5761010080835404028352916020019162000e29565b820191906000526020600020905b81548152906001019060200180831162000e0b57829003601f168201915b5050506003909301549192505060ff8116906001600160401b036101009091041686565b3362000e616001546001600160a01b031690565b6001600160a01b03161462000eb95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620004ce565b60005b81811015620008855782828281811062000eda5762000eda62002555565b905060200281019062000eee919062002680565b6007600085858581811062000f075762000f0762002555565b905060200281019062000f1b919062002680565b62000f2e90604081019060200162002284565b6001600160a01b03166001600160a01b03168152602001908152602001600020600085858581811062000f655762000f6562002555565b905060200281019062000f79919062002680565b62000f8c9060c081019060a00162002535565b6001600160401b03168152602081019190915260400160002062000fb1828262002837565b5081905062000fc081620025b0565b91505062000ebc565b600080546001600160a01b03163314620010225760405162461bcd60e51b815260206004820152601960248201527863616c6c6572206973206e6f74206d6573736167652062757360381b6044820152606401620004ce565b6001600160a01b03861660009081526005602090815260408083206001600160401b038916845290915290205460ff16620010965760405162461bcd60e51b81526020600482015260136024820152722ab730baba3437b934b9b2b21039b2b73232b960691b6044820152606401620004ce565b600080620010a78587018762002939565b91509150600080620010ba898562001624565b6002549193509150620010db906001600160a01b0380851691168362001986565b600254604051637c5141fb60e01b81526001916001600160a01b031690637c5141fb906200111490869086908f908a90600401620029a3565b6020604051808303816000875af192505050801562001152575060408051601f3d908101601f191682019092526200114f91810190620029dc565b60015b62001247573d80801562001183576040519150601f19603f3d011682016040523d82523d6000602084013e62001188565b606091505b507fbd8deeebc4a2cd5e7ce108bacfdd51d6864f4e701d33245727f3ce6a9a25c19781604051620011ba919062002615565b60405180910390a160025460405163bc886f6560e01b81526001600160a01b039091169063bc886f6590620011f890879087908a90600401620029ff565b6020604051808303816000875af115801562001218573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200123e9190620029dc565b9150506200124a565b90505b60008160028111156200126157620012616200201f565b0362001276576001955050505050506200053a565b60018160028111156200128d576200128d6200201f565b03620012a2576000955050505050506200053a565b6002816002811115620012b957620012b96200201f565b03620012ce576002955050505050506200053a565b5060009a9950505050505050505050565b6002546001600160a01b031633146200132e5760405162461bcd60e51b815260206004820152601060248201526f125b9d985b1a5908195b991c1bda5b9d60821b6044820152606401620004ce565b620013456001600160a01b03841633308562001593565b6200137b6001600160a01b0384167f000000000000000000000000ee6c6d360216f270bf9dacf85bed79c772cb9f4c84620019b8565b60405163282d3fdf60e01b81526001600160a01b038481166004830152602482018490527f000000000000000000000000ee6c6d360216f270bf9dacf85bed79c772cb9f4c169063282d3fdf906044016020604051808303816000875af1158015620013eb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200141191906200262a565b604080516000602082018190526001600160a01b03871682840152606080830185905283518084039091018152608083019093529294509091906200145d908390859060a001620025ec565b60408051601f198184030181529082905260005463299aee5160e11b8352909250620014a9918991899185916001600160a01b031690635335dca29062000ade90849060040162002615565b50505050505050565b33620014c66001546001600160a01b031690565b6001600160a01b0316146200151e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620004ce565b6001600160a01b038116620015855760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401620004ce565b620015908162001a6c565b50565b6040516001600160a01b0380851660248301528316604482015260648101829052620016009085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915262001abe565b50505050565b60005462001600908590859085906001600160a01b03168562001b9a565b60008060008060008580602001905181019062001642919062002a29565b92509250925060008360ff1660018111156200166257620016626200201f565b9194508491905060008160018111156200168057620016806200201f565b03620018d6576001600160a01b0380841660009081526007602090815260408083206001600160401b038d1684528252808320815160c081018352815460ff81161515825261010090049095169285019290925260018201805493949391840191620016ec9062002644565b80601f01602080910402602001604051908101604052809291908181526020018280546200171a9062002644565b80156200176b5780601f106200173f576101008083540402835291602001916200176b565b820191906000526020600020905b8154815290600101906020018083116200174d57829003601f168201915b50505050508152602001600282018054620017869062002644565b80601f0160208091040260200160405190810160405280929190818152602001828054620017b49062002644565b8015620018055780601f10620017d95761010080835404028352916020019162001805565b820191906000526020600020905b815481529060010190602001808311620017e757829003601f168201915b50505091835250506003919091015460ff8116602083015261010090046001600160401b031660409091015280519091506200187a5760405162461bcd60e51b815260206004820152601360248201527213595d1859185d18481a5cc81b9bdd081cd95d606a1b6044820152606401620004ce565b620018cd6040518060a001604052808360400151815260200183606001518152602001836080015160ff1681526020018b6001600160401b03168152602001866001600160a01b03168152508462001c09565b9650506200197b565b6001816001811115620018ed57620018ed6200201f565b036200014357604051637eee288d60e01b81526001600160a01b038481166004830152602482018490527f000000000000000000000000ee6c6d360216f270bf9dacf85bed79c772cb9f4c1690637eee288d90604401600060405180830381600087803b1580156200195e57600080fd5b505af115801562001973573d6000803e3d6000fd5b505050508295505b505050509250929050565b6040516001600160a01b0383166024820152604481018290526200088590849063a9059cbb60e01b90606401620015c8565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa15801562001a09573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001a2f91906200262a565b9050620016008463095ea7b360e01b8562001a4b868662002a71565b6040516001600160a01b0390921660248301526044820152606401620015c8565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600062001b15826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031662001d679092919063ffffffff16565b905080516000148062001b3957508080602001905181019062001b39919062002a87565b620008855760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401620004ce565b604051634f9e72ad60e11b81526001600160a01b03831690639f3ce55a90839062001bce9089908990899060040162002aa7565b6000604051808303818588803b15801562001be857600080fd5b505af115801562001bfd573d6000803e3d6000fd5b50505050505050505050565b60608201516001600160401b0316600090815260036020908152604080832060808601516001600160a01b0390811685529252822054168062001cfb578360405162001c559062001ef9565b62001c61919062002ada565b604051809103906000f08015801562001c7e573d6000803e3d6000fd5b506060850180516001600160401b03908116600090815260036020908152604080832060808b0180516001600160a01b03908116865291845282852080546001600160a01b03199081168a851690811790925591519751909616855260048452828520958552949092529091208054909216921691909117905590505b6040516340c10f1960e01b8152306004820152602481018490526001600160a01b038216906340c10f1990604401600060405180830381600087803b15801562001d4457600080fd5b505af115801562001d59573d6000803e3d6000fd5b509293505050505b92915050565b606062001d78848460008562001d80565b949350505050565b60608247101562001de35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401620004ce565b600080866001600160a01b0316858760405162001e01919062002b57565b60006040518083038185875af1925050503d806000811462001e40576040519150601f19603f3d011682016040523d82523d6000602084013e62001e45565b606091505b509150915062000cc6878383876060831562001ec657825160000362001ebe576001600160a01b0385163b62001ebe5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620004ce565b508162001d78565b62001d78838381511562001edd5781518083602001fd5b8060405162461bcd60e51b8152600401620004ce919062002615565b610dbb8062002b6c83390190565b60008083601f84011262001f1a57600080fd5b5081356001600160401b0381111562001f3257600080fd5b60208301915083602082850101111562001f4b57600080fd5b9250929050565b6001600160401b03811681146200159057600080fd5b6001600160a01b03811681146200159057600080fd5b6000806000806000806080878903121562001f9857600080fd5b86356001600160401b038082111562001fb057600080fd5b62001fbe8a838b0162001f07565b90985096506020890135915062001fd58262001f52565b9094506040880135908082111562001fec57600080fd5b5062001ffb89828a0162001f07565b9094509250506060870135620020118162001f68565b809150509295509295509295565b634e487b7160e01b600052602160045260246000fd5b60208101600383106200205857634e487b7160e01b600052602160045260246000fd5b91905290565b6000806000806000608086880312156200207757600080fd5b8535620020848162001f68565b94506020860135935060408601356001600160401b03811115620020a757600080fd5b620020b58882890162001f07565b9094509250506060860135620020cb8162001f68565b809150509295509295909350565b60008060208385031215620020ed57600080fd5b82356001600160401b03808211156200210557600080fd5b818501915085601f8301126200211a57600080fd5b8135818111156200212a57600080fd5b8660206060830285010111156200214057600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200217a57600080fd5b81356001600160401b038082111562002197576200219762002152565b604051601f8301601f19908116603f01168101908282118183101715620021c257620021c262002152565b81604052838152866020858801011115620021dc57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156200221557600080fd5b8535620022228162001f68565b94506020860135620022348162001f52565b93506040860135620022468162001f68565b92506060860135915060808601356001600160401b038111156200226957600080fd5b620022778882890162002168565b9150509295509295909350565b6000602082840312156200229757600080fd5b8135620022a48162001f68565b9392505050565b600080600080600080600060c0888a031215620022c757600080fd5b8735620022d48162001f68565b96506020880135620022e68162001f68565b9550604088013594506060880135620022ff8162001f52565b935060808801356001600160401b038111156200231b57600080fd5b620023298a828b0162001f07565b90945092505060a08801356200233f8162001f68565b8091505092959891949750929550565b600080604083850312156200236357600080fd5b8235620023708162001f52565b91506020830135620023828162001f68565b809150509250929050565b60008060408385031215620023a157600080fd5b8235620023ae8162001f68565b91506020830135620023828162001f52565b60005b83811015620023dd578181015183820152602001620023c3565b50506000910152565b6000815180845262002400816020860160208601620023c0565b601f01601f19169290920160200192915050565b86151581526001600160a01b038616602082015260c0604082015260006200244060c0830187620023e6565b8281036060840152620024548187620023e6565b91505060ff841660808301526001600160401b03831660a0830152979650505050505050565b600080602083850312156200248e57600080fd5b82356001600160401b0380821115620024a657600080fd5b818501915085601f830112620024bb57600080fd5b813581811115620024cb57600080fd5b8660208260051b85010111156200214057600080fd5b600080600080600060808688031215620024fa57600080fd5b8535620025078162001f68565b94506020860135620025198162001f52565b935060408601356001600160401b03811115620020a757600080fd5b6000602082840312156200254857600080fd5b8135620022a48162001f52565b634e487b7160e01b600052603260045260246000fd5b80151581146200159057600080fd5b6000602082840312156200258d57600080fd5b8135620022a4816200256b565b634e487b7160e01b600052601160045260246000fd5b600060018201620025c557620025c56200259a565b5060010190565b600060208284031215620025df57600080fd5b8151620022a48162001f68565b604081526000620026016040830185620023e6565b82810360208401526200053a8185620023e6565b602081526000620022a46020830184620023e6565b6000602082840312156200263d57600080fd5b5051919050565b600181811c908216806200265957607f821691505b6020821081036200267a57634e487b7160e01b600052602260045260246000fd5b50919050565b6000823560be198336030181126200269757600080fd5b9190910192915050565b6000808335601e19843603018112620026b957600080fd5b8301803591506001600160401b03821115620026d457600080fd5b60200191503681900382131562001f4b57600080fd5b601f8211156200088557600081815260208120601f850160051c81016020861015620027135750805b601f850160051c820191505b8181101562002734578281556001016200271f565b505050505050565b6001600160401b0383111562002756576200275662002152565b6200276e8362002767835462002644565b83620026ea565b6000601f841160018114620027a557600085156200278c5750838201355b600019600387901b1c1916600186901b17835562002802565b600083815260209020601f19861690835b82811015620027d85786850135825560209485019460019092019101620027b6565b5086821015620027f65760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60ff811681146200159057600080fd5b6000813562001d618162002809565b6000813562001d618162001f52565b813562002844816200256b565b815460ff19811691151560ff1691821783556020840135620028668162001f68565b74ffffffffffffffffffffffffffffffffffffffff008160081b16836affffffffffffffffffffff60a81b841617178455505050620028a96040830183620026a1565b620028b98183600186016200273c565b5050620028ca6060830183620026a1565b620028da8183600286016200273c565b50506003810162002903620028f26080850162002819565b825460ff191660ff91909116178255565b620008856200291560a0850162002828565b825468ffffffffffffffff00191660089190911b68ffffffffffffffff0016178255565b600080604083850312156200294d57600080fd5b82356001600160401b03808211156200296557600080fd5b620029738683870162002168565b935060208501359150808211156200298a57600080fd5b50620029998582860162002168565b9150509250929050565b6001600160a01b03851681528360208201526001600160401b0383166040820152608060608201526000620004d76080830184620023e6565b600060208284031215620029ef57600080fd5b815160038110620022a457600080fd5b6001600160a01b03841681528260208201526060604082015260006200053a6060830184620023e6565b60008060006060848603121562002a3f57600080fd5b835162002a4c8162002809565b602085015190935062002a5f8162001f68565b80925050604084015190509250925092565b8082018082111562001d615762001d616200259a565b60006020828403121562002a9a57600080fd5b8151620022a4816200256b565b6001600160a01b03841681526001600160401b03831660208201526060604082015260006200053a6060830184620023e6565b602081526000825160a0602084015262002af860c0840182620023e6565b90506020840151601f1984830301604085015262002b178282620023e6565b91505060ff60408501511660608401526001600160401b0360608501511660808401526001600160a01b0360808501511660a08401528091505092915050565b6000825162002697818460208701620023c056fe60a06040523480156200001157600080fd5b5060405162000dbb38038062000dbb8339810160408190526200003491620001fc565b805160029062000045908262000369565b5060208101516003906200005a908262000369565b5060408101516004805460608401516080948501516001600160a01b031661010002610100600160a81b03196001600160401b03909216600160a81b0260ff600160a81b03600160e81b031990931660ff90951694909417919091171691909117905533905262000435565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b0381118282101715620001015762000101620000c6565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620001325762000132620000c6565b604052919050565b600082601f8301126200014c57600080fd5b81516001600160401b03811115620001685762000168620000c6565b60206200017e601f8301601f1916820162000107565b82815285828487010111156200019357600080fd5b60005b83811015620001b357858101830151828201840152820162000196565b506000928101909101919091529392505050565b80516001600160401b0381168114620001df57600080fd5b919050565b80516001600160a01b0381168114620001df57600080fd5b6000602082840312156200020f57600080fd5b81516001600160401b03808211156200022757600080fd5b9083019060a082860312156200023c57600080fd5b62000246620000dc565b8251828111156200025657600080fd5b62000264878286016200013a565b8252506020830151828111156200027a57600080fd5b62000288878286016200013a565b6020830152506040830151915060ff82168214620002a557600080fd5b816040820152620002b960608401620001c7565b6060820152620002cc60808401620001e4565b608082015295945050505050565b600181811c90821680620002ef57607f821691505b6020821081036200031057634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200036457600081815260208120601f850160051c810160208610156200033f5750805b601f850160051c820191505b8181101562000360578281556001016200034b565b5050505b505050565b81516001600160401b03811115620003855762000385620000c6565b6200039d81620003968454620002da565b8462000316565b602080601f831160018114620003d55760008415620003bc5750858301515b600019600386901b1c1916600185901b17855562000360565b600085815260208120601f198616915b828110156200040657888601518255948401946001909101908401620003e5565b5085821015620004255787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805161095c6200045f6000396000818161024e01528181610380015261040c015261095c6000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c806370a082311161008c578063a9059cbb11610066578063a9059cbb14610206578063cab416b414610219578063d5f3948814610249578063dd62ed3e1461027057600080fd5b806370a08231146101c257806395d89b41146101eb5780639dc29fac146101f357600080fd5b806318160ddd116100c857806318160ddd1461016457806323b872dd1461017b578063313ce5671461018e57806340c10f19146101ad57600080fd5b806306fdde03146100ef578063095ea7b31461010d5780630d788c3614610130575b600080fd5b6100f76102a9565b604051610104919061078b565b60405180910390f35b61012061011b3660046107f5565b610337565b6040519015158152602001610104565b60045461014b90600160a81b900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610104565b61016d60055481565b604051908152602001610104565b61012061018936600461081f565b610351565b60045461019b9060ff1681565b60405160ff9091168152602001610104565b6101c06101bb3660046107f5565b610375565b005b61016d6101d036600461085b565b6001600160a01b031660009081526020819052604090205490565b6100f76103f4565b6101c06102013660046107f5565b610401565b6101206102143660046107f5565b610477565b6004546102319061010090046001600160a01b031681565b6040516001600160a01b039091168152602001610104565b6102317f000000000000000000000000000000000000000000000000000000000000000081565b61016d61027e36600461087d565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600280546102b6906108b0565b80601f01602080910402602001604051908101604052809291908181526020018280546102e2906108b0565b801561032f5780601f106103045761010080835404028352916020019161032f565b820191906000526020600020905b81548152906001019060200180831161031257829003601f168201915b505050505081565b600033610345818585610485565b60019150505b92915050565b60003361035f858285610579565b61036a85858561060b565b506001949350505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103aa57600080fd5b6001600160a01b038216600090815260208190526040812080548392906103d2908490610900565b9250508190555080600560008282546103eb9190610900565b90915550505050565b600380546102b6906108b0565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461043657600080fd5b6001600160a01b0382166000908152602081905260408120805483929061045e908490610913565b9250508190555080600560008282546103eb9190610913565b60003361034581858561060b565b6001600160a01b0383166104ec5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084015b60405180910390fd5b6001600160a01b03821661054d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016104e3565b6001600160a01b0392831660009081526001602090815260408083209490951682529290925291902055565b6001600160a01b03808416600090815260016020908152604080832093861683529290522054600019811461060557818110156105f85760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016104e3565b6106058484848403610485565b50505050565b6001600160a01b03831661066f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016104e3565b6001600160a01b0382166106d15760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016104e3565b6001600160a01b038316600090815260208190526040902054818110156107495760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016104e3565b6001600160a01b03808516600090815260208190526040808220858503905591851681529081208054849290610780908490610900565b909155505050505050565b600060208083528351808285015260005b818110156107b85785810183015185820160400152820161079c565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146107f057600080fd5b919050565b6000806040838503121561080857600080fd5b610811836107d9565b946020939093013593505050565b60008060006060848603121561083457600080fd5b61083d846107d9565b925061084b602085016107d9565b9150604084013590509250925092565b60006020828403121561086d57600080fd5b610876826107d9565b9392505050565b6000806040838503121561089057600080fd5b610899836107d9565b91506108a7602084016107d9565b90509250929050565b600181811c908216806108c457607f821691505b6020821081036108e457634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561034b5761034b6108ea565b8181038181111561034b5761034b6108ea56fea264697066735822122050795a9fe2ce243c123c04c8b3be3238c0fb1cbccef0c4e17160e0ba4c91412264736f6c63430008110033a2646970667358221220bee0e1b211ad5c40f9a713679b90399aa9363b048369a5226b67a8b3193dec0364736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ee6c6d360216f270bf9dacf85bed79c772cb9f4c0000000000000000000000004066d196a423b2b3b8b054f4f40efb47a74e200c
-----Decoded View---------------
Arg [0] : _vault (address): 0xee6C6d360216f270Bf9dacF85beD79c772cb9f4C
Arg [1] : _messageBus (address): 0x4066D196A423b2b3B8B054f4F40efB47a74E200C
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000ee6c6d360216f270bf9dacf85bed79c772cb9f4c
Arg [1] : 0000000000000000000000004066d196a423b2b3b8b054f4f40efb47a74e200c
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.