Source Code
Overview
ETH Balance
3.197439172569317597 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 4,690 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Bridge Native To... | 7158459 | 7 days ago | IN | 0.01604197 ETH | 0.00035607 | ||||
Bridge Native To... | 7158350 | 7 days ago | IN | 0.00202817 ETH | 0.00040153 | ||||
Bridge Native To... | 7158324 | 7 days ago | IN | 0.01110913 ETH | 0.0010794 | ||||
Bridge To Runes | 7149246 | 9 days ago | IN | 0.00104203 ETH | 0.00109179 | ||||
Bridge Native To... | 7054039 | 23 days ago | IN | 0.01103881 ETH | 0.00063069 | ||||
Bridge Native To... | 7053660 | 23 days ago | IN | 0.0210386 ETH | 0.00053937 | ||||
Bridge Native To... | 7053127 | 23 days ago | IN | 0.00303841 ETH | 0.00053399 | ||||
Bridge Native To... | 7052974 | 23 days ago | IN | 0.00303809 ETH | 0.00061055 | ||||
Bridge Native To... | 7052786 | 23 days ago | IN | 0.00461303 ETH | 0.00110566 | ||||
Bridge Native To... | 7052569 | 23 days ago | IN | 0.01161303 ETH | 0.00080839 | ||||
Bridge Native To... | 7052405 | 23 days ago | IN | 0.00261303 ETH | 0.00167324 | ||||
Bridge Native To... | 7052366 | 23 days ago | IN | 0.00107787 ETH | 0.00032081 | ||||
Bridge Native To... | 7052343 | 23 days ago | IN | 0.00203787 ETH | 0.00033292 | ||||
Bridge Native To... | 7052342 | 23 days ago | IN | 0.00203787 ETH | 0.00032935 | ||||
Bridge Native To... | 7052342 | 23 days ago | IN | 0.00203787 ETH | 0.00032935 | ||||
Bridge Native To... | 7052341 | 23 days ago | IN | 0.00203787 ETH | 0.00032935 | ||||
Bridge Native To... | 7052340 | 23 days ago | IN | 0.00203787 ETH | 0.00032935 | ||||
Bridge Native To... | 7052317 | 23 days ago | IN | 0.01103787 ETH | 0.00033056 | ||||
Bridge Native To... | 7052231 | 23 days ago | IN | 0.01161303 ETH | 0.00059923 | ||||
Bridge Native To... | 7052227 | 23 days ago | IN | 0.01123784 ETH | 0.00022243 | ||||
Bridge Native To... | 7052225 | 23 days ago | IN | 0.01113784 ETH | 0.00022045 | ||||
Bridge Native To... | 7052224 | 23 days ago | IN | 0.01203784 ETH | 0.00020209 | ||||
Bridge Native To... | 7052221 | 23 days ago | IN | 0.01303784 ETH | 0.00023009 | ||||
Bridge Native To... | 7052219 | 23 days ago | IN | 0.01103784 ETH | 0.00024548 | ||||
Bridge Native To... | 7052130 | 23 days ago | IN | 0.00133784 ETH | 0.0002139 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
7158459 | 7 days ago | 0.015 ETH | ||||
7158350 | 7 days ago | 0.001 ETH | ||||
7158324 | 7 days ago | 0.00009815 ETH | ||||
7158324 | 7 days ago | 0.01 ETH | ||||
7054039 | 23 days ago | 0.01 ETH | ||||
7053660 | 23 days ago | 0.02 ETH | ||||
7053127 | 23 days ago | 0.002 ETH | ||||
7052974 | 23 days ago | 0.002 ETH | ||||
7052825 | 23 days ago | 0.5 ETH | ||||
7052825 | 23 days ago | 0.5 ETH | ||||
7052786 | 23 days ago | 0.00059706 ETH | ||||
7052786 | 23 days ago | 0.003 ETH | ||||
7052569 | 23 days ago | 0.00059706 ETH | ||||
7052569 | 23 days ago | 0.01 ETH | ||||
7052405 | 23 days ago | 0.00059706 ETH | ||||
7052405 | 23 days ago | 0.001 ETH | ||||
7052366 | 23 days ago | 0.00004 ETH | ||||
7052343 | 23 days ago | 0.001 ETH | ||||
7052342 | 23 days ago | 0.001 ETH | ||||
7052342 | 23 days ago | 0.001 ETH | ||||
7052341 | 23 days ago | 0.001 ETH | ||||
7052340 | 23 days ago | 0.001 ETH | ||||
7052317 | 23 days ago | 0.01 ETH | ||||
7052231 | 23 days ago | 0.00059706 ETH | ||||
7052231 | 23 days ago | 0.01 ETH |
Loading...
Loading
Contract Name:
OriginalTokenBridge
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {MessagingFee, Origin} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol"; import {TokenBridgeBase} from "./TokenBridgeBase.sol"; import {IWETH} from "./interfaces/IWETH.sol"; import {IMintableBurnable} from "./interfaces/IMintableBurnable.sol"; import {ChainId} from "./libraries/ChainId.sol"; /** * @title OriginalTokenBridge * @notice Bridge for ERC20, Bitcoin, BRC-20, and Runes * - Users can: * # Bridge ERC20 <-> ERC20 * # Bridge ERC20 <-> BRC-20 * # Bridge ERC20 <-> Runes * # Bridge Native ETH * # BTC wrap / unwrap */ contract OriginalTokenBridge is TokenBridgeBase { using SafeERC20 for IERC20; /// @notice Tokens that can be bridged to the remote chain /// @dev [remote chain id] => [local token] => [bool] mapping(uint32 => mapping(address => bool)) public supportedTokens; /// @notice Tokens that can be bridged to BRC-20 /// @dev [local token] => [remote tick] mapping(address => string) public localToBrc20; /// @notice Tokens that can be bridged from BRC-20 /// @dev [remote tick] => [local token] mapping(string => address) public brc20ToLocal; /// @notice Tokens that can be bridged to Runes /// @dev [local token] => [remote tick] mapping(address => string) public localToRunes; /// @notice Tokens that can be bridged from Runes /// @dev [remote tick] => [local token] mapping(string => address) public runesToLocal; /// @notice Total value locked per each supported token /// @dev [remote chain id] => [local token] => [amount] mapping(uint32 => mapping(address => uint)) public tvls; /// @notice Total value locked to BRC-20 /// @dev [local token] => [amount] mapping(address => uint) public brc20Tvls; /// @notice Total value locked to Runes /// @dev [local token] => [amount] mapping(address => uint) public runesTvls; /// @notice Whether the transaction id has been used before mapping(string => bool) public txIdUsed; /// @notice Address of the wrapped native gas token (e.g. WETH, WBNB, WMATIC) address public immutable WETH; /// @notice Address of the WrappedBTC address public immutable BBTC; /// @notice Fee charged uint256 public fee; event SendToken( address localToken, uint32 remoteChainId, address from, address to, uint amount, uint nativeFee, uint16 referralCode ); event ReceiveToken( address localToken, uint32 remoteChainId, address to, uint amount, TokenType tokenType, string btcReceiver, uint16 referralCode ); event RegisterToken(address localToken, uint32 remoteChainId); event FeeChanged(uint256 indexed oldFee, uint256 indexed newFee); // for BRC-20 event RegisterBrc20Token(uint256 chainId, address localToken, string tick); event BridgeToBrc20( uint256 chainId, string tick, address localToken, address from, string to, uint amount, uint nativeFee, uint16 referralCode ); event Brc20Received( uint256 chainId, string tick, uint32 remoteChainId, address localToken, address to, uint amount, string txId, uint16 referralCode ); // for Runes event RegisterRunesToken(uint256 chainId, address localToken, string tick); event BridgeToRunes( uint256 chainId, string tick, address localToken, address from, string to, uint amount, uint nativeFee, uint16 referralCode ); event RunesReceived( uint256 chainId, string tick, uint32 remoteChainId, address localToken, address to, uint amount, string txId, uint16 referralCode ); event Brc20ToRunesTvlsUpdated(string brc20Tick, uint256 amount); event RunesToBrc20TvlsUpdated(string runesTick, uint256 amount); // for WrapBTC event WrapBTC( string txId, uint32 remoteChainId, address to, uint amount, uint16 referralCode ); event UnwrapBTC(string btcReceiver, uint amount, uint16 referralCode); /** * @notice Constructor * @param _endpoint LayerZero endpoint * @param _delegate The delegate capable of making OApp configurations inside of the endpoint * @param _btcBridge the btc bridge address, multisig wallet * @param _superAdmin the super admin address * @param _btcDataFeed Chainlink BTC/USD price feed * @param _nativeDataFeed Chainlink Native/USD price feed * @param _nativeDecimals Decimals of the native currency */ constructor( address _weth, address _bBTC, address _endpoint, address _delegate, address _btcBridge, address _superAdmin, address _btcDataFeed, address _nativeDataFeed, uint8 _nativeDecimals ) TokenBridgeBase( _endpoint, _delegate, _btcBridge, _superAdmin, _btcDataFeed, _nativeDataFeed, _nativeDecimals ) { if (_weth == address(0) || _bBTC == address(0)) { revert InvalidTokenAddress(); } WETH = _weth; BBTC = _bBTC; fee = 0.03 ether; } // External functions /// @dev enable to receive Native currency receive() external payable {} /** * @notice Registers a token for bridging * @param localToken address of the local token * @param remoteChainId chain id of the remote chain */ function registerToken( address localToken, uint32 remoteChainId ) external onlyOwner { if (localToken == address(0)) { revert InvalidTokenAddress(); } if (supportedTokens[remoteChainId][localToken]) { revert TokenRegistered(); } supportedTokens[remoteChainId][localToken] = true; protocolTokens[localToken] = true; emit RegisterToken(localToken, remoteChainId); } /** * @notice Registers a token for bridging to BRC-20 * @param localToken address of the local token * @param tick identifier of the brc-20 */ function registerBrc20Token( address localToken, string memory tick ) external onlyOwner { if (localToken == address(0)) { revert InvalidTokenAddress(); } if (bytes(tick).length == 0) { revert InvalidTick(); } if ( bytes(localToBrc20[localToken]).length > 0 || brc20ToLocal[tick] != address(0) ) { revert TokenRegistered(); } localToBrc20[localToken] = tick; brc20ToLocal[tick] = localToken; protocolTokens[localToken] = true; emit RegisterBrc20Token(ChainId.get(), localToken, tick); } /** * @notice Registers a token for bridging to Runes * @param localToken address of the local token * @param tick identifier of the Runes */ function registerRunesToken( address localToken, string memory tick ) external onlyOwner { if (localToken == address(0)) { revert InvalidTokenAddress(); } if (bytes(tick).length == 0) { revert InvalidTick(); } if ( bytes(localToRunes[localToken]).length > 0 || runesToLocal[tick] != address(0) ) { revert TokenRegistered(); } localToRunes[localToken] = tick; runesToLocal[tick] = localToken; protocolTokens[localToken] = true; emit RegisterRunesToken(ChainId.get(), localToken, tick); } /** * @notice Bridges ERC20 to the remote chain * Locks an ERC20 on the source chain and sends LZ message to the remote chain to mint a wrapped token * @param localToken address of local token * @param remoteChainId chain id of the remote chain * @param amount bridge amount * @param to the receiver address on the remote chain * @param referralCode referral code * @param refundAddress the refund address for the LayerZero native fee * @param options Additional options for message execution */ function bridgeToErc20( address localToken, uint32 remoteChainId, uint amount, address to, uint16 referralCode, address payable refundAddress, bytes calldata options ) external payable whenNotPaused(localToken) nonReentrant { if (!supportedTokens[remoteChainId][localToken]) { revert UnsupportedToken(); } if (amount == 0) { revert InvalidAmount(); } // estimate LayerZero native fee (uint totalFee, uint nativeFee) = estimateErc20TotalFee( remoteChainId, options ); if (msg.value < totalFee) { revert InsufficientFee(); } if (refundAddress == address(0)) { revert InvalidRefundAddress(); } // transfer token to contract IERC20(localToken).safeTransferFrom( _msgSender(), address(this), amount ); _bridgeToErc20( localToken, remoteChainId, amount, to, nativeFee, referralCode, refundAddress, options ); } /** * @notice Bridges native gas token (e.g. ETH) to the remote chain * @dev Locks WETH on the source chain and sends LZ message to the remote chain to mint a wrapped token * @param remoteChainId chain id of the remote chain * @param amount bridge amount * @param to the receiver address on the remote chain * @param referralCode referral code * @param refundAddress the refund address for the LayerZero native fee * @param options additional options for message execution */ function bridgeNativeToErc20( uint32 remoteChainId, uint amount, address to, uint16 referralCode, address payable refundAddress, bytes calldata options ) external payable whenNotPaused(WETH) nonReentrant { if (!supportedTokens[remoteChainId][WETH]) { revert UnsupportedToken(); } if (amount == 0) { revert InvalidAmount(); } if (refundAddress == address(0)) { revert InvalidRefundAddress(); } // estimate erc20 total fee (uint totalFee, uint nativeFee) = estimateErc20TotalFee( remoteChainId, options ); if (msg.value < totalFee + amount) { revert InsufficientValueSent(); } // Deposit ether to get wrapped ether, lock WETH in contract IWETH(WETH).deposit{value: amount}(); _bridgeToErc20( WETH, remoteChainId, amount, to, nativeFee, referralCode, refundAddress, options ); } /** * @notice Bridges ERC20 to BRC-20 * On the EVM side, lock the user's ERC-20, and then transfer the brc-20 to the user on the Bitcoin side * @param localToken address of the local token * @param amount bridge amount * @param to the receiver address on the Bitcoin side * @param referralCode referral code */ function bridgeToBrc20( address localToken, uint amount, string memory to, uint16 referralCode ) external payable whenNotPaused(localToken) nonReentrant { string memory tick = localToBrc20[localToken]; if (bytes(tick).length == 0) { revert UnsupportedToken(); } if (amount == 0) { revert InvalidAmount(); } if (msg.value < estimateBrc20TotalFee()) { revert InsufficientFee(); } // transfer token to contract IERC20(localToken).safeTransferFrom( _msgSender(), address(this), amount ); _bridgeToBrc20(tick, localToken, amount, to, msg.value, referralCode); } /** * @notice Bridges native ETH to BRC-20 * On the EVM side, lock the user's ERC-20, and then transfer the brc-20 to the user on the Bitcoin side * @param amount bridge amount * @param to the receiver address on the Bitcoin side * @param referralCode referral code */ function bridgeNativeToBrc20( uint amount, string memory to, uint16 referralCode ) external payable whenNotPaused(WETH) nonReentrant { string memory tick = localToBrc20[WETH]; if (bytes(tick).length == 0) { revert UnsupportedToken(); } if (amount == 0) { revert InvalidAmount(); } uint totalFee = estimateBrc20TotalFee(); if (msg.value < amount + totalFee) { revert InsufficientValueSent(); } // Deposit ether to get wrapped ether, lock WETH in contract IWETH(WETH).deposit{value: amount}(); _bridgeToBrc20(tick, WETH, amount, to, amount, referralCode); } /** * @notice Bridges ERC20 to Runes * On the EVM side, lock the user's ERC-20, and then transfer the Runes to the user on the Bitcoin side * @param localToken address of the local token * @param amount bridge amount * @param to the receiver address on the Bitcoin side * @param referralCode referral code */ function bridgeToRunes( address localToken, uint amount, string memory to, uint16 referralCode ) external payable whenNotPaused(localToken) nonReentrant { string memory tick = localToRunes[localToken]; if (bytes(tick).length == 0) { revert UnsupportedToken(); } if (amount == 0) { revert InvalidAmount(); } if (msg.value < estimateRunesTotalFee()) { revert InsufficientFee(); } // transfer token to contract IERC20(localToken).safeTransferFrom( _msgSender(), address(this), amount ); _bridgeToRunes(tick, localToken, amount, to, msg.value, referralCode); } /** * @notice Bridges native ETH to Runes * On the EVM side, lock the user's ERC-20, and then transfer the Runes to the user on the Bitcoin side * @param amount bridge amount * @param to the receiver address on the Bitcoin side * @param referralCode referral code */ function bridgeNativeToRunes( uint amount, string memory to, uint16 referralCode ) external payable whenNotPaused(WETH) nonReentrant { string memory tick = localToRunes[WETH]; if (bytes(tick).length == 0) { revert UnsupportedToken(); } if (amount == 0) { revert InvalidAmount(); } uint totalFee = estimateRunesTotalFee(); if (msg.value < amount + totalFee) { revert InsufficientValueSent(); } // Deposit ether to get wrapped ether, lock WETH in contract IWETH(WETH).deposit{value: amount}(); _bridgeToRunes(tick, WETH, amount, to, amount, referralCode); } /** * @notice Bridges BTC to the EVM chain * @param txId transaction id of the Bitcoin transaction * @param remoteChainId remote chain id of LayerZero(remoteChainId == 0, bridge to Ethereum; remoteChainId != 0, bridge to remote chain) * @param to the receiver address * @param amount the amount of wrapped BTC * @param referralCode referral code * @param refundAddress refund address for the LayerZero native fee (only for remote chain) * @param options additional options for message execution */ function wrapBTC( string memory txId, uint32 remoteChainId, address to, uint amount, uint16 referralCode, address payable refundAddress, bytes calldata options ) external payable whenNotPaused(BBTC) onlyBtcBridge { if (to == address(0)) { revert InvalidTo(); } if (amount == 0) { revert InvalidAmount(); } if (bytes(txId).length == 0) { revert InvalidTxId(); } if (txIdUsed[txId]) { revert AlreadyWrapped(); } // mark txId as used, prevent reentrancy txIdUsed[txId] = true; if (remoteChainId == 0) { // bridge to current chain, mint wrapped BTC IMintableBurnable(BBTC).mint(to, amount); } else { // bridge to remote chain if (!supportedTokens[remoteChainId][BBTC]) { revert UnsupportedToken(); } // estimate LayerZero native fee (uint nativeFee, ) = estimateBridgeFee(remoteChainId, options); if (msg.value < nativeFee) { revert InsufficientFee(); } // mint wrapped BTC, locked in the contract IMintableBurnable(BBTC).mint(address(this), amount); // bridge to erc20 _bridgeToErc20( BBTC, remoteChainId, amount, to, msg.value, referralCode, refundAddress, options ); } emit WrapBTC(txId, remoteChainId, to, amount, referralCode); } /** * @notice Unwrap bBTC to BTC * @param amount the amount of wrapped BTC * @param to the receiver address * @param referralCode referral code */ function unwrapBTC( uint amount, string memory to, uint16 referralCode ) external payable whenNotPaused(BBTC) { if (amount == 0) { revert InvalidAmount(); } if (bytes(to).length == 0) { revert InvalidTo(); } uint256 totalFee = estimateUnwrapBTCTotalFee(); if (msg.value < totalFee) { revert InsufficientFee(); } // transfer token to contract IERC20(BBTC).safeTransferFrom(_msgSender(), address(this), amount); // burn wrapped BTC IMintableBurnable(BBTC).burn(address(this), amount); emit UnwrapBTC(to, amount, referralCode); } /** * @notice Sets the fee charged for bridging * @param _fee the fee charged */ function setFee(uint256 _fee) external onlyOwner { emit FeeChanged(fee, _fee); fee = _fee; } /** * @notice Bridges Brc20 to ERC20 * Brc-20 has been received on the Bitcoin side(Unified Account), and then ERC-20 is sent to the user on the EVM side * @param _tick brc20 tick * @param _remoteChainId remote chain id (remoteChainId == 0, bridge to Ethereum; remoteChainId != 0, bridge to remote chain) * @param _to receiver address * @param _amount received amount * @param txId transaction id of the Bitcoin transaction * @param referralCode referral code * @param refundAddress refund address for the LayerZero native fee (only for remote chain) * @param options additional options for message execution */ function brc20Received( string memory _tick, uint16 _remoteChainId, address _to, uint _amount, string memory txId, uint16 referralCode, address payable refundAddress, bytes calldata options ) external payable onlyBtcBridge { address localToken = brc20ToLocal[_tick]; if (localToken == address(0)) { revert UnsupportedBrc20(); } if (globalPaused || pausedTokens[localToken]) { revert Paused(); } if (_to == address(0)) { revert InvalidTo(); } if (_amount == 0) { revert InvalidAmount(); } if (bytes(txId).length == 0) { revert InvalidTxId(); } if (txIdUsed[txId]) { revert TxIdBeenUsed(); } // mark txId as used, prevent reentrancy txIdUsed[txId] = true; // sub tvl uint tvl = brc20Tvls[localToken]; if (tvl < _amount) { revert InsufficientLiquidity(); } brc20Tvls[localToken] = tvl - _amount; if (_remoteChainId != 0) { // bridge to remote evm chain if (!supportedTokens[_remoteChainId][localToken]) { revert UnsupportedToken(); } if (refundAddress == address(0)) { revert InvalidRefundAddress(); } // estimate LayerZero native fee (uint nativeFee, ) = estimateBridgeFee(_remoteChainId, options); if (msg.value < nativeFee) { revert InsufficientFee(); } // bridge to erc20 _bridgeToErc20( localToken, _remoteChainId, _amount, _to, msg.value, referralCode, refundAddress, options ); } else { if (localToken == WETH) { // unlock ether IWETH(WETH).withdraw(_amount); (bool success, ) = payable(_to).call{value: _amount}(""); if (!success) { revert UnlockETHFail(); } } else { // bridge brc20 to current chain, unlock token IERC20(localToken).safeTransfer(_to, _amount); } } emit Brc20Received( ChainId.get(), _tick, _remoteChainId, localToken, _to, _amount, txId, referralCode ); } /** * @notice Bridges `Runes` to ERC20 (remoteChainId != 0, bridge to remote chain) * Runes has been received on the Bitcoin side(Unified Account), and then ERC-20 is sent to the user on the EVM side * @param _tick runes tick * @param _remoteChainId remote chain id * @param _to receiver address * @param _amount received amount * @param txId transaction id of the Bitcoin transaction * @param referralCode referral code * @param refundAddress refund address for the LayerZero native fee * @param options additional options for message execution */ function runesReceived( string memory _tick, uint16 _remoteChainId, address _to, uint _amount, string memory txId, uint16 referralCode, address payable refundAddress, bytes calldata options ) external payable onlyBtcBridge { address localToken = runesToLocal[_tick]; if (localToken == address(0)) { revert UnsupportedRunes(); } if (globalPaused || pausedTokens[localToken]) { revert Paused(); } if (_to == address(0)) { revert InvalidTo(); } if (_amount == 0) { revert InvalidAmount(); } if (bytes(txId).length == 0) { revert InvalidTxId(); } if (txIdUsed[txId]) { revert TxIdBeenUsed(); } // mark txId as used, prevent reentrancy txIdUsed[txId] = true; // sub tvl uint tvl = runesTvls[localToken]; if (tvl < _amount) { revert InsufficientLiquidity(); } runesTvls[localToken] = tvl - _amount; if (_remoteChainId != 0) { // bridge to remote evm chain if (!supportedTokens[_remoteChainId][localToken]) { revert UnsupportedToken(); } if (refundAddress == address(0)) { revert InvalidRefundAddress(); } // estimate LayerZero native fee (uint nativeFee, ) = estimateBridgeFee(_remoteChainId, options); if (msg.value < nativeFee) { revert InsufficientFee(); } // bridge to erc20 _bridgeToErc20( localToken, _remoteChainId, _amount, _to, msg.value, referralCode, refundAddress, options ); } else { if (localToken == WETH) { // unlock ether IWETH(WETH).withdraw(_amount); (bool success, ) = payable(_to).call{value: _amount}(""); if (!success) { revert UnlockETHFail(); } } else { // bridge runes to current chain, unlock token IERC20(localToken).safeTransfer(_to, _amount); } } emit RunesReceived( ChainId.get(), _tick, _remoteChainId, localToken, _to, _amount, txId, referralCode ); } /** * @notice Updates the TVL of BRC20 to Runes * BRC20 has been bridged to Runes, and then the TVL of BRC20 and Runes is updated * @param _tick brc20 tick * @param amount amount bridged from brc20 to runes */ function updateBrc20ToRunesTvls( string memory _tick, uint256 amount ) external onlyBtcBridge { // reduce brc20 tvl address localToken = brc20ToLocal[_tick]; if (localToken == address(0)) { revert UnsupportedBrc20(); } if (globalPaused || pausedTokens[localToken]) { revert Paused(); } uint brc20Tvl = brc20Tvls[localToken]; if (brc20Tvl < amount) { revert InsufficientLiquidity(); } brc20Tvls[localToken] = brc20Tvl - amount; // increase runes tvl string memory runesTick = localToRunes[localToken]; if (bytes(runesTick).length == 0) { revert UnsupportedRunes(); } uint runesTvl = runesTvls[localToken]; runesTvls[localToken] = runesTvl + amount; emit Brc20ToRunesTvlsUpdated(_tick, amount); } /** * @notice Updates the TVL of Runes to BRC20 * Runes has been bridged to BRC20, and then the TVL of Runes and BRC20 is updated * @param runesTick runes tick * @param amount amount bridged from runes to brc20 */ function updateRunesToBrc20Tvls( string memory runesTick, uint256 amount ) external onlyBtcBridge { // reduce runes tvl address localToken = runesToLocal[runesTick]; if (localToken == address(0)) { revert UnsupportedRunes(); } if (globalPaused || pausedTokens[localToken]) { revert Paused(); } uint runesTvl = runesTvls[localToken]; if (runesTvl < amount) { revert InsufficientLiquidity(); } runesTvls[localToken] = runesTvl - amount; // increase brc20 tvl string memory brc20Tick = localToBrc20[localToken]; if (bytes(brc20Tick).length == 0) { revert UnsupportedBrc20(); } uint brc20Tvl = brc20Tvls[localToken]; brc20Tvls[localToken] = brc20Tvl + amount; emit RunesToBrc20TvlsUpdated(runesTick, amount); } // Public functions /** * @dev Estimates the fee for bridging ERC20 to the remote chain * @param remoteChainId chain id of the remote chain * @param options Additional options for message execution */ function estimateBridgeFee( uint32 remoteChainId, bytes calldata options ) public view returns (uint256 nativeFee, uint256 lzTokenFee) { // Only the payload format matters when estimating fee, not the actual data bytes memory payload = abi.encode( PT_MINT, address(this), address(this), 0, 0 ); MessagingFee memory msgFee = _quote( remoteChainId, payload, options, false /** _payInLzToken */ ); nativeFee = msgFee.nativeFee; lzTokenFee = msgFee.lzTokenFee; } /** * @notice Estimate the total fee for bridging ERC20 to the remote chain * @param remoteChainId The remote chain id * @param options Additional options for message execution */ function estimateErc20TotalFee( uint32 remoteChainId, bytes calldata options ) public view returns (uint totalFee, uint nativeFee) { (nativeFee, ) = estimateBridgeFee(remoteChainId, options); totalFee = fee + nativeFee; } /** * @notice Estimate the total fee for bridging ERC20 to BRC20 */ function estimateBrc20TotalFee() public view returns (uint totalFee) { uint256 brc20TransferFee = getBitcoinTransferFeeInNative( brc20TransferFee ); totalFee = fee + brc20TransferFee; } /** * @notice Estimate the total fee for bridging ERC20 to Runes */ function estimateRunesTotalFee() public view returns (uint totalFee) { uint256 runesTransferFee = getBitcoinTransferFeeInNative( runesTransferFee ); totalFee = fee + runesTransferFee; } /** * @notice Estimate the total fee for unwrapping BTC */ function estimateUnwrapBTCTotalFee() public view returns (uint totalFee) { uint256 unwrapBtcFee = getBitcoinTransferFeeInNative(btcTransferFee); totalFee = fee + unwrapBtcFee; } // Internal functions /** * @notice Receives LayerZero message from the remote chain * @param _origin struct containing info about the message sender * @param payload payload data */ function _lzReceive( Origin calldata _origin, // struct containing info about the message sender bytes32, // _guid: global packet identifier bytes calldata payload, // encoded message payload being received address, // _executor: the Executor address. bytes calldata // _extraData: arbitrary data appended by the Executor ) internal override { uint32 srcChainId = _origin.srcEid; ( uint8 packetType, address token, address to, uint totalAmount, TokenType tokenType, string memory btcReceiver, uint16 referralCode, bool unwrapBtc ) = abi.decode( payload, (uint8, address, address, uint, TokenType, string, uint16, bool) ); if (globalPaused || pausedTokens[token]) { revert Paused(); } if (packetType != PT_UNLOCK) { revert UnknownPacketType(); } if (!supportedTokens[srcChainId][token]) { revert UnsupportedToken(); } if ( unwrapBtc || tokenType == TokenType.BRC20 || tokenType == TokenType.RUNES ) { if (bytes(btcReceiver).length == 0) { revert InvalidBtcReceiver(); } } else { if (to == address(0)) { revert InvalidTo(); } } // sub tvl of erc20 uint tvl = tvls[srcChainId][token]; if (tvl < totalAmount) { revert InsufficientLiquidity(); } tvls[srcChainId][token] = tvl - totalAmount; if (tokenType == TokenType.BRC20) { // directly bridge erc20 to brc20 string memory tick = localToBrc20[token]; if (bytes(tick).length == 0) { revert UnsupportedBrc20(); } // increase tvl of brc20 brc20Tvls[token] += totalAmount; emit BridgeToBrc20( ChainId.get(), tick, token, _msgSender(), btcReceiver, totalAmount, 0, referralCode ); } else if (tokenType == TokenType.RUNES) { // directly bridge erc20 to Runes string memory tick = localToRunes[token]; if (bytes(tick).length == 0) { revert UnsupportedRunes(); } // increase tvl of Runes runesTvls[token] += totalAmount; emit BridgeToRunes( ChainId.get(), tick, token, _msgSender(), btcReceiver, totalAmount, 0, referralCode ); } else if (tokenType == TokenType.ERC20) { if (token == WETH) { // unlock ether IWETH(WETH).withdraw(totalAmount); (bool success, ) = payable(to).call{value: totalAmount}(""); if (!success) { revert UnlockETHFail(); } emit ReceiveToken( address(0), srcChainId, to, totalAmount, tokenType, btcReceiver, referralCode ); } else if (token == BBTC && unwrapBtc) { // bridge bBTC to BTC // burn wrapped BTC IMintableBurnable(BBTC).burn(address(this), totalAmount); emit UnwrapBTC(btcReceiver, totalAmount, referralCode); } else { // unlock erc20 token IERC20(token).safeTransfer(to, totalAmount); emit ReceiveToken( token, srcChainId, to, totalAmount, tokenType, btcReceiver, referralCode ); } } } // Private functions /** * @notice Bridges ERC20 to the remote chain * @param localToken the local token address * @param remoteChainId the remote chain id * @param amount bridge amount * @param to the receiver address on the remote chain * @param nativeFee the native fee * @param referralCode referral code * @param refundAddress specifies the address to which any excess fees should be refunded * @param options Additional options for message execution */ function _bridgeToErc20( address localToken, uint32 remoteChainId, uint amount, address to, uint nativeFee, uint16 referralCode, address refundAddress, bytes memory options ) private { if (to == address(0)) { revert InvalidTo(); } tvls[remoteChainId][localToken] += amount; bytes memory payload = abi.encode( PT_MINT, localToken, to, amount, referralCode ); _lzSend( remoteChainId, payload, options, MessagingFee(nativeFee, 0), payable(refundAddress) ); emit SendToken( localToken, remoteChainId, _msgSender(), to, amount, nativeFee, referralCode ); } /** * @notice Bridges ERC20 to BRC20 * @param tick brc20 tick * @param token the local token * @param amount bridge amount * @param to the receiver address on the Bitcoin side * @param nativeFee the native fee * @param referralCode referral code */ function _bridgeToBrc20( string memory tick, address token, uint amount, string memory to, uint nativeFee, uint16 referralCode ) private { if (bytes(to).length == 0) { revert InvalidTo(); } brc20Tvls[token] += amount; emit BridgeToBrc20( ChainId.get(), tick, token, _msgSender(), to, amount, nativeFee, referralCode ); } /** * @notice Bridges ERC20 to Runes * @param tick runes tick * @param token the local token * @param amount bridge amount * @param to the receiver address on the Bitcoin side * @param nativeFee the native fee * @param referralCode referral code */ function _bridgeToRunes( string memory tick, address token, uint amount, string memory to, uint nativeFee, uint16 referralCode ) private { if (bytes(to).length == 0) { revert InvalidTo(); } runesTvls[token] += amount; emit BridgeToRunes( ChainId.get(), tick, token, _msgSender(), to, amount, nativeFee, referralCode ); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { IMessageLibManager } from "./IMessageLibManager.sol"; import { IMessagingComposer } from "./IMessagingComposer.sol"; import { IMessagingChannel } from "./IMessagingChannel.sol"; import { IMessagingContext } from "./IMessagingContext.sol"; struct MessagingParams { uint32 dstEid; bytes32 receiver; bytes message; bytes options; bool payInLzToken; } struct MessagingReceipt { bytes32 guid; uint64 nonce; MessagingFee fee; } struct MessagingFee { uint256 nativeFee; uint256 lzTokenFee; } struct Origin { uint32 srcEid; bytes32 sender; uint64 nonce; } interface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext { event PacketSent(bytes encodedPayload, bytes options, address sendLibrary); event PacketVerified(Origin origin, address receiver, bytes32 payloadHash); event PacketDelivered(Origin origin, address receiver); event LzReceiveAlert( address indexed receiver, address indexed executor, Origin origin, bytes32 guid, uint256 gas, uint256 value, bytes message, bytes extraData, bytes reason ); event LzTokenSet(address token); event DelegateSet(address sender, address delegate); function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory); function send( MessagingParams calldata _params, address _refundAddress ) external payable returns (MessagingReceipt memory); function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external; function verifiable(Origin calldata _origin, address _receiver) external view returns (bool); function initializable(Origin calldata _origin, address _receiver) external view returns (bool); function lzReceive( Origin calldata _origin, address _receiver, bytes32 _guid, bytes calldata _message, bytes calldata _extraData ) external payable; // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external; function setLzToken(address _lzToken) external; function lzToken() external view returns (address); function nativeToken() external view returns (address); function setDelegate(address _delegate) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { Origin } from "./ILayerZeroEndpointV2.sol"; interface ILayerZeroReceiver { function allowInitializePath(Origin calldata _origin) external view returns (bool); function nextNonce(uint32 _eid, bytes32 _sender) external view returns (uint64); function lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; struct SetConfigParam { uint32 eid; uint32 configType; bytes config; } interface IMessageLibManager { struct Timeout { address lib; uint256 expiry; } event LibraryRegistered(address newLib); event DefaultSendLibrarySet(uint32 eid, address newLib); event DefaultReceiveLibrarySet(uint32 eid, address newLib); event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry); event SendLibrarySet(address sender, uint32 eid, address newLib); event ReceiveLibrarySet(address receiver, uint32 eid, address newLib); event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout); function registerLibrary(address _lib) external; function isRegisteredLibrary(address _lib) external view returns (bool); function getRegisteredLibraries() external view returns (address[] memory); function setDefaultSendLibrary(uint32 _eid, address _newLib) external; function defaultSendLibrary(uint32 _eid) external view returns (address); function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _gracePeriod) external; function defaultReceiveLibrary(uint32 _eid) external view returns (address); function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external; function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry); function isSupportedEid(uint32 _eid) external view returns (bool); function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) external view returns (bool); /// ------------------- OApp interfaces ------------------- function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external; function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib); function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool); function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external; function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault); function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _expiry) external; function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry); function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external; function getConfig( address _oapp, address _lib, uint32 _eid, uint32 _configType ) external view returns (bytes memory config); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingChannel { event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce); event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash); event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash); function eid() external view returns (uint32); // this is an emergency function if a message cannot be verified for some reasons // required to provide _nextNonce to avoid race condition function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external; function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external; function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external; function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32); function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64); function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64); function inboundPayloadHash( address _receiver, uint32 _srcEid, bytes32 _sender, uint64 _nonce ) external view returns (bytes32); function lazyInboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingComposer { event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message); event ComposeDelivered(address from, address to, bytes32 guid, uint16 index); event LzComposeAlert( address indexed from, address indexed to, address indexed executor, bytes32 guid, uint16 index, uint256 gas, uint256 value, bytes message, bytes extraData, bytes reason ); function composeQueue( address _from, address _to, bytes32 _guid, uint16 _index ) external view returns (bytes32 messageHash); function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external; function lzCompose( address _from, address _to, bytes32 _guid, uint16 _index, bytes calldata _message, bytes calldata _extraData ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingContext { function isSendingMessage() external view returns (bool); function getSendContext() external view returns (uint32 dstEid, address sender); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { ILayerZeroEndpointV2 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; /** * @title IOAppCore */ interface IOAppCore { // Custom error messages error OnlyPeer(uint32 eid, bytes32 sender); error NoPeer(uint32 eid); error InvalidEndpointCall(); error InvalidDelegate(); // Event emitted when a peer (OApp) is set for a corresponding endpoint event PeerSet(uint32 eid, bytes32 peer); /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol contract. * @return receiverVersion The version of the OAppReceiver.sol contract. */ function oAppVersion() external view returns (uint64 senderVersion, uint64 receiverVersion); /** * @notice Retrieves the LayerZero endpoint associated with the OApp. * @return iEndpoint The LayerZero endpoint as an interface. */ function endpoint() external view returns (ILayerZeroEndpointV2 iEndpoint); /** * @notice Retrieves the peer (OApp) associated with a corresponding endpoint. * @param _eid The endpoint ID. * @return peer The peer address (OApp instance) associated with the corresponding endpoint. */ function peers(uint32 _eid) external view returns (bytes32 peer); /** * @notice Sets the peer address (OApp instance) for a corresponding endpoint. * @param _eid The endpoint ID. * @param _peer The address of the peer to be associated with the corresponding endpoint. */ function setPeer(uint32 _eid, bytes32 _peer) external; /** * @notice Sets the delegate address for the OApp Core. * @param _delegate The address of the delegate to be set. */ function setDelegate(address _delegate) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { ILayerZeroReceiver, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroReceiver.sol"; interface IOAppReceiver is ILayerZeroReceiver { /** * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint. * @param _origin The origin information containing the source endpoint and sender address. * - srcEid: The source chain endpoint ID. * - sender: The sender address on the src chain. * - nonce: The nonce of the message. * @param _message The lzReceive payload. * @param _sender The sender address. * @return isSender Is a valid sender. * * @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer. * @dev The default sender IS the OAppReceiver implementer. */ function isComposeMsgSender( Origin calldata _origin, bytes calldata _message, address _sender ) external view returns (bool isSender); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; // @dev Import the 'MessagingFee' and 'MessagingReceipt' so it's exposed to OApp implementers // solhint-disable-next-line no-unused-import import { OAppSender, MessagingFee, MessagingReceipt } from "./OAppSender.sol"; // @dev Import the 'Origin' so it's exposed to OApp implementers // solhint-disable-next-line no-unused-import import { OAppReceiver, Origin } from "./OAppReceiver.sol"; import { OAppCore } from "./OAppCore.sol"; /** * @title OApp * @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality. */ abstract contract OApp is OAppSender, OAppReceiver { /** * @dev Constructor to initialize the OApp with the provided endpoint and owner. * @param _endpoint The address of the LOCAL LayerZero endpoint. * @param _delegate The delegate capable of making OApp configurations inside of the endpoint. */ constructor(address _endpoint, address _delegate) OAppCore(_endpoint, _delegate) {} /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol implementation. * @return receiverVersion The version of the OAppReceiver.sol implementation. */ function oAppVersion() public pure virtual override(OAppSender, OAppReceiver) returns (uint64 senderVersion, uint64 receiverVersion) { return (SENDER_VERSION, RECEIVER_VERSION); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { IOAppCore, ILayerZeroEndpointV2 } from "./interfaces/IOAppCore.sol"; /** * @title OAppCore * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations. */ abstract contract OAppCore is IOAppCore, Ownable { // The LayerZero endpoint associated with the given OApp ILayerZeroEndpointV2 public immutable endpoint; // Mapping to store peers associated with corresponding endpoints mapping(uint32 eid => bytes32 peer) public peers; /** * @dev Constructor to initialize the OAppCore with the provided endpoint and delegate. * @param _endpoint The address of the LOCAL Layer Zero endpoint. * @param _delegate The delegate capable of making OApp configurations inside of the endpoint. * * @dev The delegate typically should be set as the owner of the contract. */ constructor(address _endpoint, address _delegate) { endpoint = ILayerZeroEndpointV2(_endpoint); if (_delegate == address(0)) revert InvalidDelegate(); endpoint.setDelegate(_delegate); } /** * @notice Sets the peer address (OApp instance) for a corresponding endpoint. * @param _eid The endpoint ID. * @param _peer The address of the peer to be associated with the corresponding endpoint. * * @dev Only the owner/admin of the OApp can call this function. * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp. * @dev Set this to bytes32(0) to remove the peer address. * @dev Peer is a bytes32 to accommodate non-evm chains. */ function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner { _setPeer(_eid, _peer); } /** * @notice Sets the peer address (OApp instance) for a corresponding endpoint. * @param _eid The endpoint ID. * @param _peer The address of the peer to be associated with the corresponding endpoint. * * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp. * @dev Set this to bytes32(0) to remove the peer address. * @dev Peer is a bytes32 to accommodate non-evm chains. */ function _setPeer(uint32 _eid, bytes32 _peer) internal virtual { peers[_eid] = _peer; emit PeerSet(_eid, _peer); } /** * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set. * ie. the peer is set to bytes32(0). * @param _eid The endpoint ID. * @return peer The address of the peer associated with the specified endpoint. */ function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) { bytes32 peer = peers[_eid]; if (peer == bytes32(0)) revert NoPeer(_eid); return peer; } /** * @notice Sets the delegate address for the OApp. * @param _delegate The address of the delegate to be set. * * @dev Only the owner/admin of the OApp can call this function. * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract. */ function setDelegate(address _delegate) public onlyOwner { endpoint.setDelegate(_delegate); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { IOAppReceiver, Origin } from "./interfaces/IOAppReceiver.sol"; import { OAppCore } from "./OAppCore.sol"; /** * @title OAppReceiver * @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers. */ abstract contract OAppReceiver is IOAppReceiver, OAppCore { // Custom error message for when the caller is not the registered endpoint/ error OnlyEndpoint(address addr); // @dev The version of the OAppReceiver implementation. // @dev Version is bumped when changes are made to this contract. uint64 internal constant RECEIVER_VERSION = 2; /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol contract. * @return receiverVersion The version of the OAppReceiver.sol contract. * * @dev Providing 0 as the default for OAppSender version. Indicates that the OAppSender is not implemented. * ie. this is a RECEIVE only OApp. * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions. */ function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) { return (0, RECEIVER_VERSION); } /** * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint. * @dev _origin The origin information containing the source endpoint and sender address. * - srcEid: The source chain endpoint ID. * - sender: The sender address on the src chain. * - nonce: The nonce of the message. * @dev _message The lzReceive payload. * @param _sender The sender address. * @return isSender Is a valid sender. * * @dev Applications can optionally choose to implement separate composeMsg senders that are NOT the bridging layer. * @dev The default sender IS the OAppReceiver implementer. */ function isComposeMsgSender( Origin calldata /*_origin*/, bytes calldata /*_message*/, address _sender ) public view virtual returns (bool) { return _sender == address(this); } /** * @notice Checks if the path initialization is allowed based on the provided origin. * @param origin The origin information containing the source endpoint and sender address. * @return Whether the path has been initialized. * * @dev This indicates to the endpoint that the OApp has enabled msgs for this particular path to be received. * @dev This defaults to assuming if a peer has been set, its initialized. * Can be overridden by the OApp if there is other logic to determine this. */ function allowInitializePath(Origin calldata origin) public view virtual returns (bool) { return peers[origin.srcEid] == origin.sender; } /** * @notice Retrieves the next nonce for a given source endpoint and sender address. * @dev _srcEid The source endpoint ID. * @dev _sender The sender address. * @return nonce The next nonce. * * @dev The path nonce starts from 1. If 0 is returned it means that there is NO nonce ordered enforcement. * @dev Is required by the off-chain executor to determine the OApp expects msg execution is ordered. * @dev This is also enforced by the OApp. * @dev By default this is NOT enabled. ie. nextNonce is hardcoded to return 0. */ function nextNonce(uint32 /*_srcEid*/, bytes32 /*_sender*/) public view virtual returns (uint64 nonce) { return 0; } /** * @dev Entry point for receiving messages or packets from the endpoint. * @param _origin The origin information containing the source endpoint and sender address. * - srcEid: The source chain endpoint ID. * - sender: The sender address on the src chain. * - nonce: The nonce of the message. * @param _guid The unique identifier for the received LayerZero message. * @param _message The payload of the received message. * @param _executor The address of the executor for the received message. * @param _extraData Additional arbitrary data provided by the corresponding executor. * * @dev Entry point for receiving msg/packet from the LayerZero endpoint. */ function lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) public payable virtual { // Ensures that only the endpoint can attempt to lzReceive() messages to this OApp. if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender); // Ensure that the sender matches the expected peer for the source endpoint. if (_getPeerOrRevert(_origin.srcEid) != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender); // Call the internal OApp implementation of lzReceive. _lzReceive(_origin, _guid, _message, _executor, _extraData); } /** * @dev Internal function to implement lzReceive logic without needing to copy the basic parameter validation. */ function _lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) internal virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { MessagingParams, MessagingFee, MessagingReceipt } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; import { OAppCore } from "./OAppCore.sol"; /** * @title OAppSender * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint. */ abstract contract OAppSender is OAppCore { using SafeERC20 for IERC20; // Custom error messages error NotEnoughNative(uint256 msgValue); error LzTokenUnavailable(); // @dev The version of the OAppSender implementation. // @dev Version is bumped when changes are made to this contract. uint64 internal constant SENDER_VERSION = 1; /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol contract. * @return receiverVersion The version of the OAppReceiver.sol contract. * * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented. * ie. this is a SEND only OApp. * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions */ function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) { return (SENDER_VERSION, 0); } /** * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation. * @param _dstEid The destination endpoint ID. * @param _message The message payload. * @param _options Additional options for the message. * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens. * @return fee The calculated MessagingFee for the message. * - nativeFee: The native fee for the message. * - lzTokenFee: The LZ token fee for the message. */ function _quote( uint32 _dstEid, bytes memory _message, bytes memory _options, bool _payInLzToken ) internal view virtual returns (MessagingFee memory fee) { return endpoint.quote( MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken), address(this) ); } /** * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message. * @param _dstEid The destination endpoint ID. * @param _message The message payload. * @param _options Additional options for the message. * @param _fee The calculated LayerZero fee for the message. * - nativeFee: The native fee. * - lzTokenFee: The lzToken fee. * @param _refundAddress The address to receive any excess fee values sent to the endpoint. * @return receipt The receipt for the sent message. * - guid: The unique identifier for the sent message. * - nonce: The nonce of the sent message. * - fee: The LayerZero fee incurred for the message. */ function _lzSend( uint32 _dstEid, bytes memory _message, bytes memory _options, MessagingFee memory _fee, address _refundAddress ) internal virtual returns (MessagingReceipt memory receipt) { // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint. uint256 messageValue = _payNative(_fee.nativeFee); if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee); return // solhint-disable-next-line check-send-result endpoint.send{ value: messageValue }( MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0), _refundAddress ); } /** * @dev Internal function to pay the native fee associated with the message. * @param _nativeFee The native fee to be paid. * @return nativeFee The amount of native currency paid. * * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction, * this will need to be overridden because msg.value would contain multiple lzFees. * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency. * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees. * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time. */ function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) { if (msg.value != _nativeFee) revert NotEnoughNative(msg.value); return _nativeFee; } /** * @dev Internal function to pay the LZ token fee associated with the message. * @param _lzTokenFee The LZ token fee to be paid. * * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint. * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend(). */ function _payLzToken(uint256 _lzTokenFee) internal virtual { // @dev Cannot cache the token because it is not immutable in the endpoint. address lzToken = endpoint.lzToken(); if (lzToken == address(0)) revert LzTokenUnavailable(); // Pay LZ token fee by sending tokens to the endpoint. IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (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. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ 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]. * * CAUTION: See Security Considerations above. */ 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 (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; /** * @dev Bridge roles. */ abstract contract BridgeRoles is Context { /// @notice Only super admin can recover ETH, and rescue ERC20 tokens address private _superAdmin; /// @notice Used to perform transactions related to Bitcoin /// @notice wrapBTC, brc20Received, runesReceived, updateBrc20ToRunesTvls, updateRunesToBrc20Tvls address private _btcBridge; error CallerNotSuperAdmin(); error CallerNotBtcBridge(); error ZeroAddress(); event SuperAdminTransferred( address indexed previousSuperAdmin, address indexed newSuperAdmin ); event BtcBridgeTransferred( address indexed previousBridge, address indexed newBridge ); /** * @dev Initializes the btc bridge and super admin. */ constructor(address superAdmin_, address btcBridge_) { if (btcBridge_ == address(0) || superAdmin_ == address(0)) { revert ZeroAddress(); } _transferSuperAdmin(superAdmin_); _transferBtcBridge(btcBridge_); } /// @dev Throws if called by any account other than the super admin modifier onlySuperAdmin() { _checkSuperAdmin(); _; } /** * @dev Throws if called by any account other than the btc bridge. */ modifier onlyBtcBridge() { _checkBtcBridge(); _; } /** * @dev Returns the address of the current super admin. */ function superAdmin() external view virtual returns (address) { return _superAdmin; } /** * @dev Returns the address of the current btc bridge. */ function btcBridge() external view virtual returns (address) { return _btcBridge; } /** * @dev Throws if the sender is not the super admin. */ function _checkSuperAdmin() internal view virtual { if (_superAdmin != _msgSender()) { revert CallerNotSuperAdmin(); } } /** * @dev Throws if the sender is not the btc bridge. */ function _checkBtcBridge() internal view virtual { if (_btcBridge != _msgSender()) { revert CallerNotBtcBridge(); } } /** * @dev Transfers super admin to a new account (`newSuperAdmin`). * Can only be called by the current btc bridge. */ function transferSuperAdmin( address newSuperAdmin ) external virtual onlySuperAdmin { if (newSuperAdmin == address(0)) { revert ZeroAddress(); } _transferSuperAdmin(newSuperAdmin); } /** * @dev Transfers btc bridge to a new account (`newBtcBridge`). * Can only be called by the current btc bridge. */ function transferBtcBridge( address newBtcBridge ) external virtual onlyBtcBridge { if (newBtcBridge == address(0)) { revert ZeroAddress(); } _transferBtcBridge(newBtcBridge); } /** * @dev Transfers super admin to a new account (`newSuperAdmin`). * Internal function without access restriction. */ function _transferSuperAdmin(address newSuperAdmin) internal virtual { address oldSuperAdmin = _superAdmin; _superAdmin = newSuperAdmin; emit SuperAdminTransferred(oldSuperAdmin, newSuperAdmin); } /** * @dev Transfers btc bridge to a new account (`newBtcBridge`). * Internal function without access restriction. */ function _transferBtcBridge(address newBtcBridge) internal virtual { address oldBtcBridge = _btcBridge; _btcBridge = newBtcBridge; emit BtcBridgeTransferred(oldBtcBridge, newBtcBridge); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; // solhint-disable-next-line interface-starts-with-i interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData(uint80 _roundId) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; /** * @title Mintalbe and Burnable token interface * @author Beyond */ interface IMintableBurnable { function mint(address to, uint256 amount) external; function burn(address from, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /// @title Interface for WETH and other wrapped native gas tokens (e.g., WBNB, WAVAX, etc.) interface IWETH { /// @notice Deposit ether to get wrapped ether function deposit() external payable; /// @notice Withdraw wrapped ether to get ether function withdraw(uint) external; /// @notice Returns the amount of tokens owned by `account` function balanceOf(address account) external view returns (uint256); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.20; /// @title Function for getting the current chain ID library ChainId { /// @dev Gets the current chain ID /// @return chainId The current chain ID function get() internal view returns (uint256 chainId) { assembly { chainId := chainid() } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import {OApp, MessagingFee} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol"; import {MessagingParams, MessagingReceipt} from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {BridgeRoles} from "./access/BridgeRoles.sol"; import {AggregatorV3Interface} from "./interfaces/AggregatorV3Interface.sol"; /** * @title TokenBridgeBase * @notice An abstract contract containing a common functionality used by OriginalTokenBridge and WrappedTokenBridge */ abstract contract TokenBridgeBase is BridgeRoles, OApp, ReentrancyGuard { using SafeCast for int256; using SafeERC20 for IERC20; /// @notice A packet type used to identify messages requesting minting of wrapped tokens uint8 public constant PT_MINT = 0; /// @notice A packet type used to identify messages requesting unlocking of original tokens uint8 public constant PT_UNLOCK = 1; // Enum representing token type enum TokenType { ERC20, BRC20, RUNES } /// @notice Tokens that are paused mapping(address => bool) public pausedTokens; /// @notice Tokens that are registered as protocol tokens mapping(address => bool) public protocolTokens; /// @notice Global pause state bool public globalPaused; /// @notice Chainlink data feed(BTC / USD) AggregatorV3Interface internal btcDataFeed; /// @notice Chainlink data feed(Native Currency / USD) AggregatorV3Interface internal nativeDataFeed; /// @notice brc-20 transfer total fee in satoshi uint256 public brc20TransferFee; /// @notice runes transfer total fee in satoshi uint256 public runesTransferFee; /// @notice bitcoin transfer total fee in satoshi uint256 public btcTransferFee; /// @notice Decimals of native currency uint8 internal nativeDecimals; // define custom errors error InvalidWethAddress(); error InsufficientValueSent(); error InvalidTokenAddress(); error TokenRegistered(); error InvalidTick(); error UnsupportedToken(); error InsufficientFee(); error InvalidRefundAddress(); error InvalidTo(); error InvalidAmount(); error Paused(); error UnknownPacketType(); error InvalidBtcReceiver(); error InsufficientLiquidity(); error UnsupportedBrc20(); error UnsupportedRunes(); error InvalidTxId(); error TxIdBeenUsed(); error RecoverETHFailed(); error InvalidRemoteTokenAddress(); error CanNotBridgedToBrc20(); error CanNotBridgedToRunes(); error UnlockETHFail(); error CanRescueNonProtocolTokens(); error AlreadyWrapped(); error AlreadyUnwrapped(); event SetGlobalPause(bool paused); event SetTokenPause(address token, bool paused); event Withdraw(address indexed to, address indexed token, uint256 amount); // event of contract event WithdrawCoins(address indexed sender, uint256 amount); event Brc20TransferFeeSet(uint256 brc20TransferFee); event RunesTransferFeeSet(uint256 runesTransferFee); event BtcTransferFeeSet(uint256 btcTransferFee); modifier whenNotPaused(address _token) { if (globalPaused || pausedTokens[_token]) { revert Paused(); } _; } /** * @notice Constructor * @param _endpoint LayerZero endpoint * @param _delegate The delegate capable of making OApp configurations inside of the endpoint * @param _btcBridge the btc bridge address * @param _superAdmin the super admin address * @param _btcDataFeed Chainlink BTC/USD price feed * @param _nativeDataFeed Chainlink Native/USD price feed * @param _nativeDecimals Decimals of the native currency */ constructor( address _endpoint, address _delegate, address _btcBridge, address _superAdmin, address _btcDataFeed, address _nativeDataFeed, uint8 _nativeDecimals ) BridgeRoles(_superAdmin, _btcBridge) OApp(_endpoint, _delegate) { btcDataFeed = AggregatorV3Interface(_btcDataFeed); nativeDataFeed = AggregatorV3Interface(_nativeDataFeed); nativeDecimals = _nativeDecimals; } // External functions /** * @notice Sets the global pause state * @param _paused The pause state */ function setGlobalPause(bool _paused) external onlyOwner { globalPaused = _paused; emit SetGlobalPause(_paused); } /** * @notice Sets the pause state for a specific token * @param _token the token address * @param _paused the pause state */ function setTokenPause(address _token, bool _paused) external onlyOwner { pausedTokens[_token] = _paused; emit SetTokenPause(_token, _paused); } /** * @notice Withdraws the specified amount of native currency * @param amount The amount of token to transfer */ function recoverETH(uint256 amount) external onlySuperAdmin { uint256 balance = address(this).balance; if (amount > balance) { revert InvalidAmount(); } // solhint-disable-next-line avoid-low-level-calls (bool success, ) = _msgSender().call{value: amount}(""); if (!success) { revert RecoverETHFailed(); } emit WithdrawCoins(_msgSender(), amount); } /** * @notice Rescue ERC20 tokens sent to contract by mistake (Only non-protocol tokens can rescue). * @param token The address of the token * @param to The address of the recipient * @param amount The amount of token to transfer */ function rescueTokens( address token, address to, uint256 amount ) external onlySuperAdmin { if (protocolTokens[token]) { revert CanRescueNonProtocolTokens(); } IERC20(token).safeTransfer(to, amount); emit Withdraw(to, token, amount); } /** * @notice Set transfer fee for BRC-20 * @param _brc20TransferFee Transfer fee for BRC-20 in satoshi */ function setBrc20TransferFee(uint256 _brc20TransferFee) external onlyOwner { brc20TransferFee = _brc20TransferFee; emit Brc20TransferFeeSet(_brc20TransferFee); } /** * @notice Set transfer fee for Runes * @param _runesTransferFee Transfer fee for Runes in satoshi */ function setRunesTransferFee(uint256 _runesTransferFee) external onlyOwner { runesTransferFee = _runesTransferFee; emit RunesTransferFeeSet(_runesTransferFee); } /** * @notice Set transfer fee for BTC * @param _btcTransferFee Transfer fee for BTC in satoshi */ function setBtcTransferFee(uint256 _btcTransferFee) external onlyOwner { btcTransferFee = _btcTransferFee; emit BtcTransferFeeSet(_btcTransferFee); } // Public functions /** * @notice Returns the BRC-20/Runes/Bitcoin transfer fee in native currency * @param transferFeeInSatoshi The transfer fee in satoshi (btcTransferFee, brc20TransferFee, runesTransferFee) */ function getBitcoinTransferFeeInNative( uint256 transferFeeInSatoshi ) public view returns (uint256) { // BTC / USD int btcAnswer = getChainlinkDataFeedLatestAnswer(btcDataFeed); // Native Currency / USD int nativeAnswer = getChainlinkDataFeedLatestAnswer(nativeDataFeed); return ((transferFeeInSatoshi * btcAnswer.toUint256() * (10 ** nativeDecimals)) / 10 ** 8) / nativeAnswer.toUint256(); } /// @dev Overrides the renounce ownership logic inherited from openZeppelin `Ownable` function renounceOwnership() public override onlyOwner {} // Internal functions /** * Returns the latest answer * @param dataFeed Chainlink data feed * @return answer The latest answer */ function getChainlinkDataFeedLatestAnswer( AggregatorV3Interface dataFeed ) internal view returns (int) { // prettier-ignore ( /* uint80 roundId */, int answer, /* uint startedAt */, /* uint updatedAt */, /* uint80 answeredInRound */ ) = dataFeed.latestRoundData(); return answer; } /** * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message. * @param _dstEid The destination endpoint ID. * @param _message The message payload. * @param _options Additional options for the message. * @param _fee The calculated LayerZero fee for the message. * - nativeFee: The native fee. * - lzTokenFee: The lzToken fee. * @param _refundAddress The address to receive any excess fee values sent to the endpoint. * @return receipt The receipt for the sent message. * - guid: The unique identifier for the sent message. * - nonce: The nonce of the sent message. * - fee: The LayerZero fee incurred for the message. */ function _lzSend( uint32 _dstEid, bytes memory _message, bytes memory _options, MessagingFee memory _fee, address _refundAddress ) internal override returns (MessagingReceipt memory receipt) { // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint. return // solhint-disable-next-line check-send-result endpoint.send{value: _fee.nativeFee}( MessagingParams( _dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0 ), _refundAddress ); } }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_bBTC","type":"address"},{"internalType":"address","name":"_endpoint","type":"address"},{"internalType":"address","name":"_delegate","type":"address"},{"internalType":"address","name":"_btcBridge","type":"address"},{"internalType":"address","name":"_superAdmin","type":"address"},{"internalType":"address","name":"_btcDataFeed","type":"address"},{"internalType":"address","name":"_nativeDataFeed","type":"address"},{"internalType":"uint8","name":"_nativeDecimals","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyUnwrapped","type":"error"},{"inputs":[],"name":"AlreadyWrapped","type":"error"},{"inputs":[],"name":"CallerNotBtcBridge","type":"error"},{"inputs":[],"name":"CallerNotSuperAdmin","type":"error"},{"inputs":[],"name":"CanNotBridgedToBrc20","type":"error"},{"inputs":[],"name":"CanNotBridgedToRunes","type":"error"},{"inputs":[],"name":"CanRescueNonProtocolTokens","type":"error"},{"inputs":[],"name":"InsufficientFee","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientValueSent","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidBtcReceiver","type":"error"},{"inputs":[],"name":"InvalidDelegate","type":"error"},{"inputs":[],"name":"InvalidEndpointCall","type":"error"},{"inputs":[],"name":"InvalidRefundAddress","type":"error"},{"inputs":[],"name":"InvalidRemoteTokenAddress","type":"error"},{"inputs":[],"name":"InvalidTick","type":"error"},{"inputs":[],"name":"InvalidTo","type":"error"},{"inputs":[],"name":"InvalidTokenAddress","type":"error"},{"inputs":[],"name":"InvalidTxId","type":"error"},{"inputs":[],"name":"InvalidWethAddress","type":"error"},{"inputs":[],"name":"LzTokenUnavailable","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"NoPeer","type":"error"},{"inputs":[{"internalType":"uint256","name":"msgValue","type":"uint256"}],"name":"NotEnoughNative","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"OnlyEndpoint","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"}],"name":"OnlyPeer","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"RecoverETHFailed","type":"error"},{"inputs":[],"name":"TokenRegistered","type":"error"},{"inputs":[],"name":"TxIdBeenUsed","type":"error"},{"inputs":[],"name":"UnknownPacketType","type":"error"},{"inputs":[],"name":"UnlockETHFail","type":"error"},{"inputs":[],"name":"UnsupportedBrc20","type":"error"},{"inputs":[],"name":"UnsupportedRunes","type":"error"},{"inputs":[],"name":"UnsupportedToken","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"string","name":"tick","type":"string"},{"indexed":false,"internalType":"uint32","name":"remoteChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"localToken","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"txId","type":"string"},{"indexed":false,"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"Brc20Received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"brc20Tick","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Brc20ToRunesTvlsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"brc20TransferFee","type":"uint256"}],"name":"Brc20TransferFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"string","name":"tick","type":"string"},{"indexed":false,"internalType":"address","name":"localToken","type":"address"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"string","name":"to","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativeFee","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"BridgeToBrc20","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"string","name":"tick","type":"string"},{"indexed":false,"internalType":"address","name":"localToken","type":"address"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"string","name":"to","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativeFee","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"BridgeToRunes","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousBridge","type":"address"},{"indexed":true,"internalType":"address","name":"newBridge","type":"address"}],"name":"BtcBridgeTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"btcTransferFee","type":"uint256"}],"name":"BtcTransferFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"FeeChanged","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":false,"internalType":"uint32","name":"eid","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"peer","type":"bytes32"}],"name":"PeerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"localToken","type":"address"},{"indexed":false,"internalType":"uint32","name":"remoteChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"enum TokenBridgeBase.TokenType","name":"tokenType","type":"uint8"},{"indexed":false,"internalType":"string","name":"btcReceiver","type":"string"},{"indexed":false,"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"ReceiveToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"localToken","type":"address"},{"indexed":false,"internalType":"string","name":"tick","type":"string"}],"name":"RegisterBrc20Token","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"localToken","type":"address"},{"indexed":false,"internalType":"string","name":"tick","type":"string"}],"name":"RegisterRunesToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"localToken","type":"address"},{"indexed":false,"internalType":"uint32","name":"remoteChainId","type":"uint32"}],"name":"RegisterToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"string","name":"tick","type":"string"},{"indexed":false,"internalType":"uint32","name":"remoteChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"localToken","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"string","name":"txId","type":"string"},{"indexed":false,"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"RunesReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"runesTick","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RunesToBrc20TvlsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"runesTransferFee","type":"uint256"}],"name":"RunesTransferFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"localToken","type":"address"},{"indexed":false,"internalType":"uint32","name":"remoteChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativeFee","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"SendToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"SetGlobalPause","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"SetTokenPause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousSuperAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newSuperAdmin","type":"address"}],"name":"SuperAdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"btcReceiver","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"UnwrapBTC","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawCoins","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"txId","type":"string"},{"indexed":false,"internalType":"uint32","name":"remoteChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"WrapBTC","type":"event"},{"inputs":[],"name":"BBTC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PT_MINT","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PT_UNLOCK","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"origin","type":"tuple"}],"name":"allowInitializePath","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_tick","type":"string"},{"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"string","name":"txId","type":"string"},{"internalType":"uint16","name":"referralCode","type":"uint16"},{"internalType":"address payable","name":"refundAddress","type":"address"},{"internalType":"bytes","name":"options","type":"bytes"}],"name":"brc20Received","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"brc20ToLocal","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"brc20TransferFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"brc20Tvls","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"to","type":"string"},{"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"bridgeNativeToBrc20","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"remoteChainId","type":"uint32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint16","name":"referralCode","type":"uint16"},{"internalType":"address payable","name":"refundAddress","type":"address"},{"internalType":"bytes","name":"options","type":"bytes"}],"name":"bridgeNativeToErc20","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"to","type":"string"},{"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"bridgeNativeToRunes","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"to","type":"string"},{"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"bridgeToBrc20","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint32","name":"remoteChainId","type":"uint32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint16","name":"referralCode","type":"uint16"},{"internalType":"address payable","name":"refundAddress","type":"address"},{"internalType":"bytes","name":"options","type":"bytes"}],"name":"bridgeToErc20","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"to","type":"string"},{"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"bridgeToRunes","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"btcBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"btcTransferFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract ILayerZeroEndpointV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"estimateBrc20TotalFee","outputs":[{"internalType":"uint256","name":"totalFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"remoteChainId","type":"uint32"},{"internalType":"bytes","name":"options","type":"bytes"}],"name":"estimateBridgeFee","outputs":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"remoteChainId","type":"uint32"},{"internalType":"bytes","name":"options","type":"bytes"}],"name":"estimateErc20TotalFee","outputs":[{"internalType":"uint256","name":"totalFee","type":"uint256"},{"internalType":"uint256","name":"nativeFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"estimateRunesTotalFee","outputs":[{"internalType":"uint256","name":"totalFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"estimateUnwrapBTCTotalFee","outputs":[{"internalType":"uint256","name":"totalFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"transferFeeInSatoshi","type":"uint256"}],"name":"getBitcoinTransferFeeInNative","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"address","name":"_sender","type":"address"}],"name":"isComposeMsgSender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"localToBrc20","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"localToRunes","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"nextNonce","outputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oAppVersion","outputs":[{"internalType":"uint64","name":"senderVersion","type":"uint64"},{"internalType":"uint64","name":"receiverVersion","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pausedTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"peers","outputs":[{"internalType":"bytes32","name":"peer","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"string","name":"tick","type":"string"}],"name":"registerBrc20Token","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"string","name":"tick","type":"string"}],"name":"registerRunesToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint32","name":"remoteChainId","type":"uint32"}],"name":"registerToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_tick","type":"string"},{"internalType":"uint16","name":"_remoteChainId","type":"uint16"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"string","name":"txId","type":"string"},{"internalType":"uint16","name":"referralCode","type":"uint16"},{"internalType":"address payable","name":"refundAddress","type":"address"},{"internalType":"bytes","name":"options","type":"bytes"}],"name":"runesReceived","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"runesToLocal","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"runesTransferFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"runesTvls","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_brc20TransferFee","type":"uint256"}],"name":"setBrc20TransferFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_btcTransferFee","type":"uint256"}],"name":"setBtcTransferFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"}],"name":"setDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setGlobalPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"bytes32","name":"_peer","type":"bytes32"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_runesTransferFee","type":"uint256"}],"name":"setRunesTransferFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setTokenPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"superAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"address","name":"","type":"address"}],"name":"supportedTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newBtcBridge","type":"address"}],"name":"transferBtcBridge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSuperAdmin","type":"address"}],"name":"transferSuperAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"address","name":"","type":"address"}],"name":"tvls","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"txIdUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"to","type":"string"},{"internalType":"uint16","name":"referralCode","type":"uint16"}],"name":"unwrapBTC","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"_tick","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"updateBrc20ToRunesTvls","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"runesTick","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"updateRunesToBrc20Tvls","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"txId","type":"string"},{"internalType":"uint32","name":"remoteChainId","type":"uint32"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint16","name":"referralCode","type":"uint16"},{"internalType":"address payable","name":"refundAddress","type":"address"},{"internalType":"bytes","name":"options","type":"bytes"}],"name":"wrapBTC","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60e0346200037757601f6200447138819003918201601f1916830192916001600160401b0391828511848610176200037c578161012092859260409788528339810103126200037757620000538262000392565b90620000626020840162000392565b926200007085820162000392565b906200007f6060820162000392565b6200008d6080830162000392565b936200009c60a0840162000392565b620000aa60c0850162000392565b92610100620000bc60e0870162000392565b9501519560ff871680970362000377576001600160a01b03978816801580156200036c575b6200035b578896959492878d9593819360009783895497169b8c9160018060a01b03199d8e8a16178b555197167f0f62530a074f4e1e883a8c916fa7f8639d52598edb7f9b5aa3148d991db5610d8a80a382600154828d821617600155167ffe89f6b8b3c79299e51301ea59956d9f4f6c40a14c27dc1bb6f4de8511fe80c48980a3600254338b821617600255823391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08980a316608052169081156200034c5750876080511690813b156200034857839291602484928e51968793849263ca5eb5e160e01b845260048401525af180156200033e57908895949392916200030e575b505060016004555060078054610100600160a81b031916600892831b610100600160a81b031617905580549093169116179055600c805460ff19169190911790558181161590811562000302575b50620002f15760a05260c052666a94d74f430000601655516140c99081620003a88239608051818181610a3701528181611dd7015281816128ae015281816139ac0152613c66015260a051818181610b8f01528181610c19015281816110220152818161171b01528181611cd8015281816124040152612b85015260c051818181610b4a01528181611187015281816113e7015281816114ff01528181611547015281816115a20152818161161f0152818161167f0152612ca20152f35b8251630f58058360e11b8152600490fd5b90508216153862000233565b90918093949550116200032a57508852849190388080620001e5565b634e487b7160e01b81526041600452602490fd5b8b513d84823e3d90fd5b8380fd5b632d618d8160e21b8152600490fd5b8b5163d92e233d60e01b8152600490fd5b5088841615620000e1565b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b0382168203620003775756fe6080604052600436101561001b575b361561001957600080fd5b005b6000803560e01c80630a1cdedd14612f8d5780630c6dd9fd14612f2057806313137d651461285357806317442b70146128315780631ffcdacc1461280857806329575f6a146127e157806330049a99146125b85780633400288b146125435780633456681f1461250a57806338e298441461227d5780633aab16bf146122425780633f7edb01146121a15780633f8976e714612100578063403f203914611ff15780634162b79714611fb857806344a59e7a14611f9757806346f6f9b514611f7b5780634b77fd8c14611f195780634da50b9b14611e065780635e280f1114611dc15780635fcf695414611cca57806360893a6414611c8b57806361a552dc14611c6857806366ab147014611a1957806368ea28b0146119fd57806369a6b3db1461199957806369fe0e2d1461194e578063715018a6146119325780637d25a05e1461190c578063801e27aa146118ee57806382413eac1461189557806382f81e2c1461187757806384abb7ad1461180e578063879bd5b11461170d5780638b762d5e146116bf5780638cf39750146112dc5780638da5cb5b146112b35780639ac46b0c146112935780639fa18e7314611179578063a0d300db14610e6c578063a34195de14610e4b578063aa293c6814610df8578063aaa2565714610da5578063ab11c84b14610d7c578063ad38983614610bbe578063ad5c464814610b79578063b7b91f4814610b34578063bb0b6a5314610aff578063c5e1669714610acb578063c663f8bc14610aad578063ca5eb5e114610a0a578063cb8d3b1f14610981578063cea9d26f146108e2578063d333555314610855578063d4c1de9614610769578063d683047314610700578063ddca3f43146106e2578063e325c1021461065f578063e3ea50e614610638578063e8a77319146105ea578063ed79444814610489578063ee7a45961461044a578063f2fde38b14610385578063f5d328521461032d5763ff7bd03d146102f2575061000e565b3461032a57606036600319011261032a57604060209163ffffffff6103156134f4565b16815260038352205460405190602435148152f35b80fd5b503461032a57604036600319011261032a5760406103496131ef565b9163ffffffff610357613033565b93168152600d602052209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b503461032a57602036600319011261032a5761039f612fdb565b6103a761353f565b6001600160a01b039081169081156103f657600254826001600160601b0360a01b821617600255167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b503461032a57602036600319011261032a5760209060ff906040906001600160a01b03610475612fdb565b168152600584522054166040519015158152f35b503461032a5761049836613446565b906104a161406d565b604051908051916020926104b881838686016133aa565b600f90820190815281900383019020546001600160a01b03169182156105d85760ff6007541680156105c3575b6105b15782855260138152604085205484811061059f57846105069161385f565b8386526013825260408620556010815261052260408620613304565b511561058d577f6b39fd225531170ecf6b0e90d2dd9aea69d840f4ad8386607d6d796caedc9248938361058394875260148352610563826040892054613815565b9087526014835260408720556040519384936040855260408501906133cd565b918301520390a180f35b60405163dd4fba9d60e01b8152600490fd5b60405163bb55fd2760e01b8152600490fd5b6040516313d0ff5960e31b8152600490fd5b508285526005815260ff6040862054166104e5565b604051636836902f60e01b8152600490fd5b503461032a57602036600319011261032a577fd18deff1242be1004442079420ded12d884c5acb1d5645366eb935a1a137e3ce602060043561062a61353f565b80600b55604051908152a180f35b503461032a57602036600319011261032a576020610657600435613ee0565b604051908152f35b503461032a57602036600319011261032a57610679612fdb565b61068161406d565b6001600160a01b039081169081156106d057600154826001600160601b0360a01b821617600155167ffe89f6b8b3c79299e51301ea59956d9f4f6c40a14c27dc1bb6f4de8511fe80c48380a380f35b60405163d92e233d60e01b8152600490fd5b503461032a578060031936011261032a576020601654604051908152f35b503461032a57602036600319011261032a57600435906001600160401b03821161032a5760206107333660048501613192565b8161074760405192838151938492016133aa565b600f90820190815281900382019020546040516001600160a01b039091168152f35b503461032a57604036600319011261032a57610783612fdb565b61078b613202565b9061079461353f565b6001600160a01b03169081156108435763ffffffff1690818352602090600d82526040842081600052825260ff6040600020541661083157826040927fabe08574bb9012ad7bf75950900dba182a5acc179e7dff4f1419d9c7dd292e07948652600d81528386208360005281528360002060ff1990600182825416179055838752600682526001858820918254161790558351928352820152a180f35b604051630aca00b560e41b8152600490fd5b604051630f58058360e11b8152600490fd5b503461032a57602036600319011261032a57600435610872614048565b4781116108d0578180808084335af161088961374c565b50156108be576040519081527f998c1d4558d59dad65b19a98dc38b7be7da91872c437602b882f3fe9b012af1660203392a280f35b604051632245761f60e11b8152600490fd5b60405163162908e360e11b8152600490fd5b503461032a57606036600319011261032a576108fc612fdb565b610904613033565b9060443590610911614048565b6001600160a01b039081168085526006602052604085205490939060ff1661096f577f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb918161096385602094886138ce565b6040519485521692a380f35b6040516364c6c5af60e11b8152600490fd5b503461032a57604036600319011261032a5761099b612fdb565b60243590811515809203610a05577fb1656bd3b50ddb6b12ef259c86e9cb359952b53c4403cfb5a83e23c515a35e22916040916109d661353f565b60018060a01b031690818552600560205282852060ff1981541660ff831617905582519182526020820152a180f35b600080fd5b503461032a57602036600319011261032a5780610a25612fdb565b610a2d61353f565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169190823b15610aa8576024849283604051958694859363ca5eb5e160e01b85521660048401525af18015610a9d57610a8d5750f35b610a969061308a565b61032a5780f35b6040513d84823e3d90fd5b505050fd5b503461032a578060031936011261032a576020600b54604051908152f35b503461032a576040610ae5610adf366134b8565b9161390a565b50610af281601654613815565b9082519182526020820152f35b503461032a57602036600319011261032a57604060209163ffffffff610b236131ef565b168152600383522054604051908152f35b503461032a578060031936011261032a576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461032a578060031936011261032a576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5060c036600319011261032a57610bd36131ef565b60243590610bdf61301d565b60643561ffff81168103610a0557610bf5613007565b60a4356001600160401b038111610d7857610c1490369060040161305d565b9390957f00000000000000000000000000000000000000000000000000000000000000009560ff600754168015610d59575b6105b157610c526135bf565b63ffffffff81168952600d602052604089209360018060a01b0390818916958660005260205260ff6040600020541615610d475783156108d05716958615610d3557610c9f818a8461390a565b5094610cb684610cb188601654613815565b613815565b3410610d2357808b913b15610d1f57818591600460405180948193630d0e30db60e41b83525af18015610a9d57610d07575b5050610cff98610cf991369161315b565b96613b2d565b600160045580f35b610d109061308a565b610d1b578938610ce8565b8980fd5b5080fd5b60405163a5fb6be960e01b8152600490fd5b60405163717f139360e11b8152600490fd5b60405163350b944160e11b8152600490fd5b506001600160a01b03871689526005602052604089205460ff16610c46565b8680fd5b503461032a578060031936011261032a576020610657610d9d600954613ee0565b601654613815565b503461032a57602036600319011261032a57610df490610de0906040906001600160a01b03610dd2612fdb565b168152601060205220613304565b6040519182916020835260208301906133cd565b0390f35b503461032a57604036600319011261032a576040610e146131ef565b9163ffffffff610e22613033565b931681526012602052209060018060a01b03166000526020526020604060002054604051908152f35b503461032a578060031936011261032a576020610657610d9d600b54613ee0565b50610e7636613226565b610e8798969195929894939461406d565b6040518751610e9a818360208c016133aa565b600f9082019081528190036020019020546001600160a01b03169081156105d85760ff600754168015611163575b6105b1576001600160a01b038316156111515783156108d05784511561113f5760ff6040516020818851610eff8183858d016133aa565b81016015815203019020541661112d576040516020818751610f248183858c016133aa565b81016015815203019020600160ff19825416179055818b52601360205260408b205484811061059f5784610f579161385f565b828c52601360205260408c205561ffff8916998a15611017578a8c52600d60205260408c208360005260205260ff6040600020541615610d47576001600160a01b0316998a15610d3557610fac82898361390a565b503410611006577f9deadd1c613e22cde00a3cd2e97e3188edcf234e9f019a736b4812e2c1591a8c9a87610fe86110009a610ff395369161315b565b928688349288613b2d565b604051978897468961386c565b0390a180f35b60405162976f7560e21b8152600490fd5b5091985094508890507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168086036110f557803b15610d1f57818091602460405180948193632e1a7d4d60e01b83528860048401525af18015610a9d576110dd575b50808080846001600160a01b038c165af161109a61374c565b50156110cb577f9deadd1c613e22cde00a3cd2e97e3188edcf234e9f019a736b4812e2c1591a8c9661100094610ff3565b6040516364eefe4560e01b8152600490fd5b6110e69061308a565b6110f1578738611081565b8780fd5b50508684611128837f9deadd1c613e22cde00a3cd2e97e3188edcf234e9f019a736b4812e2c1591a8c9a611000986138ce565b610ff3565b604051637b7d123560e11b8152600490fd5b604051635d4e0b5360e01b8152600490fd5b604051630521f43160e31b8152600490fd5b50818b52600560205260ff60408c205416610ec8565b5061118336613477565b91907f000000000000000000000000000000000000000000000000000000000000000060ff600754168015611274575b6105b15782156108d057815115611151576111d2610d9d600b54613ee0565b34106110065784906001600160a01b03166111ef84303384613615565b803b15610d1f57604051632770a7eb60e21b8152306004820152602481018590529082908290604490829084905af18015610a9d5761125c575b50506110007f0146b632afdb6e46c1215c95eb6b39d9f439e67b687d7d499bd6a0441c5735909360405193849384613838565b6112659061308a565b611270578338611229565b8380fd5b506001600160a01b03811685526005602052604085205460ff166111b3565b503461032a5760406112a7610adf366134b8565b82519182526020820152f35b503461032a578060031936011261032a576002546040516001600160a01b039091168152602090f35b5060e036600319011261032a576001600160401b036004358181116116bb57611309903690600401613192565b611311613202565b61131961301d565b92611322613215565b9061132b612ff1565b9060c435908111610d785761134490369060040161305d565b60ff60075416801561167c575b6105b15761135d61406d565b6001600160a01b0387161561115157606435156108d05785511561113f5760405160ff875191602081818b01946113958183886133aa565b81016015815203019020541661166a5760206113bc91604051809381928b519283916133aa565b81016015815203019020600160ff1982541617905563ffffffff8516156000146114e15750869150507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15610d1f576040516340c10f1960e01b81526001600160a01b038716600482015260643560248201529082908290604490829084905af18015610a9d576114c3575b50509061ffff61149a93927f58c5f63c547f733187f13f3945ac85668fc5dfc499a92668068ab4d96f7ea240955b63ffffffff60405196879660a0885260a08801906133cd565b941660208601526001600160a01b0316604085015260643560608501521660808301520390a180f35b6114d0909493929461308a565b6114dd5790918438611453565b8480fd5b63ffffffff85979495168852600d6020526040882060018060a01b037f00000000000000000000000000000000000000000000000000000000000000001660005260205260ff6040600020541615610d475761153e81838961390a565b503410611006577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163b156110f1576040516340c10f1960e01b8152306004820152606435602482015288908181604481836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af18015610a9d57611648575b50509261164361ffff9361160c61149a9897947f58c5f63c547f733187f13f3945ac85668fc5dfc499a92668068ab4d96f7ea2409a97369161315b565b906001600160a01b03168434856064358a7f0000000000000000000000000000000000000000000000000000000000000000613b2d565b611481565b61165990989592949796939861308a565b6110f15792959093949187386115cf565b6040516304f78f7d60e41b8152600490fd5b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031688526005602052604088205460ff16611351565b8280fd5b503461032a57602036600319011261032a577f371575ff48070c3a186a41fa4a051e9bd9695cc6d58b4c13791e366913ec8c7860206004356116ff61353f565b80600a55604051908152a180f35b5061171736613477565b90917f00000000000000000000000000000000000000000000000000000000000000009260ff6007541680156117ef575b6105b1576117546135bf565b6001600160a01b038416808652600e6020526040862061177390613304565b90815115610d475783156108d057611798611792610d9d600954613ee0565b85613815565b3410610d23578087913b15610d1f57818591600460405180948193630d0e30db60e41b83525af18015610a9d576117d7575b5050610cff948391613e0f565b6117e09061308a565b6117eb5785386117ca565b8580fd5b506001600160a01b03841685526005602052604085205460ff16611748565b503461032a57602036600319011261032a57600435906001600160401b03821161032a5760206118413660048501613192565b8161185560405192838151938492016133aa565b601190820190815281900382019020546040516001600160a01b039091168152f35b503461032a578060031936011261032a576020600a54604051908152f35b503461032a57366003190160a08112610d1f5760601361032a576064356001600160401b038111610d1f576118ce90369060040161305d565b505060206118da613007565b6040516001600160a01b0390911630148152f35b503461032a578060031936011261032a576020600954604051908152f35b503461032a57604036600319011261032a576020906119296131ef565b50604051908152f35b503461032a578060031936011261032a5761194b61353f565b80f35b503461032a57602036600319011261032a5760043561196b61353f565b806016547f5fc463da23c1b063e66f9e352006a7fbe8db7223c455dc429e881a2dfe2f94f18480a360165580f35b503461032a57602036600319011261032a57600435801515809103610a055760207f5362d4bd13945e8d116b90d83a7050fa61ceb02bb79bfae783377adb46916d94916119e461353f565b60ff196007541660ff821617600755604051908152a180f35b503461032a578060031936011261032a57602060405160018152f35b503461032a57611a28366131b0565b611a3392919261353f565b6001600160a01b0392808416801561084357825115611c5657808452602094600e8652611a6360408620546132ca565b1590811591611c2c575b5061083157808452600e85526040842083516001600160401b038111611c1857611a9782546132ca565b601f8111611bd5575b5086601f8211600114611b4f579181600694928899947f0fb40cd98da6acecd96260ef53ad7139c1f4d565241278a46ece82fbdae6fc979991611b44575b508160011b916000199060031b1c19161790555b60405182818751611b068183858c016133aa565b8101600f815203019020816001600160601b0360a01b82541617905586525260408420600160ff198254161790556110006040519283924684613597565b905087015138611ade565b82875287872090601f198316885b818110611bbe5750927f0fb40cd98da6acecd96260ef53ad7139c1f4d565241278a46ece82fbdae6fc9798999492600192826006989610611ba5575b5050811b019055611af2565b89015160001960f88460031b161c191690553880611b99565b91928a60018192868c015181550194019201611b5d565b828752878720601f830160051c810191898410611c0e575b601f0160051c01905b818110611c035750611aa0565b878155600101611bf6565b9091508190611bed565b634e487b7160e01b86526041600452602486fd5b905060405186818651611c428183858b016133aa565b8101600f8152030190205416151538611a6d565b6040516333a3bdff60e21b8152600490fd5b503461032a578060031936011261032a57602060ff600754166040519015158152f35b503461032a57602036600319011261032a5760209060ff906040906001600160a01b03611cb6612fdb565b168152600684522054166040519015158152f35b50611cd436613477565b90917f00000000000000000000000000000000000000000000000000000000000000009260ff600754168015611da2575b6105b157611d116135bf565b6001600160a01b038416808652601060205260408620611d3090613304565b90815115610d475783156108d057611d4f611792610d9d600a54613ee0565b3410610d23578087913b15610d1f57818591600460405180948193630d0e30db60e41b83525af18015610a9d57611d8e575b5050610cff948391613e79565b611d979061308a565b6117eb578538611d81565b506001600160a01b03841685526005602052604085205460ff16611d05565b503461032a578060031936011261032a576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5060e036600319011261032a57611e1b612fdb565b611e23613202565b906001600160a01b036064356044358282168203610a0557611e43613215565b91611e4c612ff1565b9160c4356001600160401b038111611f1557611e6c90369060040161305d565b97909560ff600754168015611efd575b6105b157611e886135bf565b63ffffffff82168a52600d60205260408a2090808916918260005260205260ff6040600020541615610d475783156108d057611ec58a898561390a565b5095611ed387601654613815565b34106110065716968715610d3557610cff99611ef685610cf99430903390613615565b369161315b565b508088168a52600560205260ff60408b205416611e7c565b8880fd5b503461032a57602036600319011261032a57600435906001600160401b03821161032a57602060ff611f6582611f523660048801613192565b81604051938285809451938492016133aa565b8101601581520301902054166040519015158152f35b503461032a578060031936011261032a57602090604051908152f35b503461032a578060031936011261032a576020610657610d9d600a54613ee0565b503461032a57602036600319011261032a576020906040906001600160a01b03611fe0612fdb565b168152601483522054604051908152f35b503461032a5761200036613446565b9061200961406d565b6040519080519160209261202081838686016133aa565b601190820190815281900383019020546001600160a01b031691821561058d5760ff6007541680156120eb575b6105b15782855260148152604085205484811061059f578461206e9161385f565b838652601482526040862055600e815261208a60408620613304565b51156105d8577fa75e52d94defea74c89d66fabe973e2d214241c54756b59e2ae5b301b4dbdba49383610583948752601383526120cb826040892054613815565b9087526013835260408720556040519384936040855260408501906133cd565b508285526005815260ff60408620541661204d565b5061210a366133f2565b91929060ff600754168015612182575b6105b1576121266135bf565b6001600160a01b038216808652600e6020526040862090949061214890613304565b92835115610d475781156108d057612164610d9d600954613ee0565b34106110065761217b82610cff9730903390613615565b3493613e0f565b506001600160a01b03821685526005602052604085205460ff1661211a565b506121ab366133f2565b91929060ff600754168015612223575b6105b1576121c76135bf565b6001600160a01b0382168086526010602052604086209094906121e990613304565b92835115610d475781156108d057612205610d9d600a54613ee0565b34106110065761221c82610cff9730903390613615565b3493613e79565b506001600160a01b03821685526005602052604085205460ff166121bb565b503461032a57602036600319011261032a57610df490610de0906040906001600160a01b0361226f612fdb565b168152600e60205220613304565b5061228736613226565b61229898969195929894939461406d565b60405187516122ab818360208c016133aa565b60119082019081528190036020019020546001600160a01b031690811561058d5760ff6007541680156124f4575b6105b1576001600160a01b038316156111515783156108d05784511561113f5760ff60405160208188516123108183858d016133aa565b81016015815203019020541661112d5760405160208187516123358183858c016133aa565b81016015815203019020600160ff19825416179055818b52601460205260408b205484811061059f57846123689161385f565b828c52601460205260408c205561ffff8916998a156123f9578a8c52600d60205260408c208360005260205260ff6040600020541615610d47576001600160a01b0316998a15610d35576123bd82898361390a565b503410611006577f335053ef368b8e10c38ca548e91f7fd4dd09802d68e273c2c94f60bcb302c3ef9a87610fe86110009a610ff395369161315b565b5091985094508890507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168086036124c157803b15610d1f57818091602460405180948193632e1a7d4d60e01b83528860048401525af18015610a9d576124ad575b50808080846001600160a01b038c165af161247c61374c565b50156110cb577f335053ef368b8e10c38ca548e91f7fd4dd09802d68e273c2c94f60bcb302c3ef9661100094610ff3565b6124b69061308a565b6110f1578738612463565b50508684611128837f335053ef368b8e10c38ca548e91f7fd4dd09802d68e273c2c94f60bcb302c3ef9a611000986138ce565b50818b52600560205260ff60408c2054166122d9565b503461032a57602036600319011261032a576020906040906001600160a01b03612532612fdb565b168152601383522054604051908152f35b503461032a57604036600319011261032a577f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b61257e6131ef565b6024359061258a61353f565b63ffffffff168084526003602090815260408086208490558051928352908201929092529081908101611000565b503461032a576125c7366131b0565b6125d292919261353f565b6001600160a01b0392808416801561084357825115611c56578084526020946010865261260260408620546132ca565b15908115916127b7575b5061083157808452601085526040842083516001600160401b038111611c185761263682546132ca565b601f8111612774575b5086601f82116001146126ee579181600694928899947fff3862ec7ba8a30d15808fdfff5539e5492b1af4fb550d9ee24d5a5958b7a05499916126e3575b508160011b916000199060031b1c19161790555b604051828187516126a58183858c016133aa565b81016011815203019020816001600160601b0360a01b82541617905586525260408420600160ff198254161790556110006040519283924684613597565b90508701513861267d565b82875287872090601f198316885b81811061275d5750927fff3862ec7ba8a30d15808fdfff5539e5492b1af4fb550d9ee24d5a5958b7a05498999492600192826006989610612744575b5050811b019055612691565b89015160001960f88460031b161c191690553880612738565b91928a60018192868c0151815501940192016126fc565b828752878720601f830160051c8101918984106127ad575b601f0160051c01905b8181106127a2575061263f565b878155600101612795565b909150819061278c565b9050604051868186516127cd8183858b016133aa565b81016011815203019020541615153861260c565b503461032a578060031936011261032a57546040516001600160a01b039091168152602090f35b503461032a578060031936011261032a576001546040516001600160a01b039091168152602090f35b503461032a578060031936011261032a57604080516001815260026020820152f35b50366003190160e08112610d1f5760601361032a576001600160401b036084358181116116bb5761288890369060040161305d565b612890612ff1565b5060c4358381116114dd576128a990369060040161305d565b5050337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031603612f08576128eb6128e66134f4565b613507565b602435809103612ed457506128fe6134f4565b90820192610100838503126114dd5782359160ff831683036117eb5761292660208501613049565b9361293360408201613049565b926003608083013510159687611f155760a0830135918211611f155761295a918301613192565b9260c08201359461ffff86168603611f155760e08301358015159003611f155760ff600754168015612eb5575b6105b15760ff6001911603612ea35763ffffffff83168852600d60209081526040808a206001600160a01b0389168b5290915288205460ff1615610d475760e08201358015612e92575b878115612e7e575b5015612e5e57835115612e4c575b63ffffffff83168852601260209081526040808a206001600160a01b0389168b529091528820546060830135979088811061059f5788612a269161385f565b63ffffffff85168a52601260209081526040808c206001600160a01b038b168d529091528a2055612e38576080820135600103612ae6575050506001600160a01b0383168552600e60205260408520612a7e90613304565b918251156105d8577faa37b49eafeac48f132d97d137275bc85ff34a908842ef8315c476099c39268f946110009260018060a01b0386168852601360205260408820612acb838254613815565b905560405195869533916001600160a01b0316904688613acf565b6080820135600203612b60575050506001600160a01b0383168552601060205260408520612b1390613304565b9182511561058d577fc95a75fe1f519ea51604d41bd3d4344af8fbe2f375cd0c7a8e14d17e24bea718946110009260018060a01b0386168852601460205260408820612acb838254613815565b909193929594608083013515612b7b575b5050505050505080f35b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116919081168203612c9457508088913b15610d1f57818091602460405180948193632e1a7d4d60e01b83528c60048401525af18015610a9d57612c80575b50506001600160a01b0316938680808084895af1612bff61374c565b50156110cb577f56e20f170e9c90c8d90b8c5cd4d1e164c2566c12df53734662f03d00003fe95795608061ffff93612c699363ffffffff98604051998a9960008b521660208a0152604089015260608801520135608086015260e060a086015260e08501906133cd565b911660c08301520390a15b38808080808080612b71565b612c899061308a565b610d78578638612be3565b939796946001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811695919491939192508316851480612e2d575b15612d935750505050803b1561127057604051632770a7eb60e21b8152306004820152602481018490529084908290604490829084905af18015612d8857612d53575b50612d4b7f0146b632afdb6e46c1215c95eb6b39d9f439e67b687d7d499bd6a0441c573590939460405193849384613838565b0390a1612c74565b7f0146b632afdb6e46c1215c95eb6b39d9f439e67b687d7d499bd6a0441c57359093612d81612d4b9261308a565b9350612d18565b6040513d86823e3d90fd5b7f56e20f170e9c90c8d90b8c5cd4d1e164c2566c12df53734662f03d00003fe95797989450612e1e92959161ffff949760809260018060a01b0316612de1828260018060a01b038c166138ce565b63ffffffff6040519a8b9a60018060a01b03168b521660208a0152604089015260608801520135608086015260e060a086015260e08501906133cd565b911660c08301520390a1612c74565b5060e0820135612cd5565b634e487b7160e01b88526021600452602488fd5b60405163ecd987b560e01b8152600490fd5b6001600160a01b0381166129e757604051630521f43160e31b8152600490fd5b9050612e38576002608083013514876129d9565b5087965060808201356001146129d1565b60405163fe3e832760e01b8152600490fd5b506001600160a01b03871689526005602052604089205460ff16612987565b612edc6134f4565b60405163309afaf360e21b815263ffffffff9190911660048201526024810191909152604490fd5b0390fd5b6040516391ac5e4f60e01b8152336004820152602490fd5b503461032a57602036600319011261032a57612f3a612fdb565b612f42614048565b6001600160a01b039081169081156106d05782546001600160a01b0319811683178455167f0f62530a074f4e1e883a8c916fa7f8639d52598edb7f9b5aa3148d991db5610d8380a380f35b503461032a57602036600319011261032a577f660ff051b38f76351c8ee1877577ca6b1f289c7b967cc2d2d657eb9561eefafd6020600435612fcd61353f565b80600955604051908152a180f35b600435906001600160a01b0382168203610a0557565b60a435906001600160a01b0382168203610a0557565b608435906001600160a01b0382168203610a0557565b604435906001600160a01b0382168203610a0557565b602435906001600160a01b0382168203610a0557565b35906001600160a01b0382168203610a0557565b9181601f84011215610a05578235916001600160401b038311610a055760208381860195010111610a0557565b6001600160401b03811161309d57604052565b634e487b7160e01b600052604160045260246000fd5b60a081019081106001600160401b0382111761309d57604052565b604081019081106001600160401b0382111761309d57604052565b606081019081106001600160401b0382111761309d57604052565b60c081019081106001600160401b0382111761309d57604052565b90601f801991011681019081106001600160401b0382111761309d57604052565b6001600160401b03811161309d57601f01601f191660200190565b92919261316782613140565b91613175604051938461311f565b829481845281830111610a05578281602093846000960137010152565b9080601f83011215610a05578160206131ad9335910161315b565b90565b906040600319830112610a05576004356001600160a01b0381168103610a055791602435906001600160401b038211610a05576131ad91600401613192565b6004359063ffffffff82168203610a0557565b6024359063ffffffff82168203610a0557565b6084359061ffff82168203610a0557565b610100600319820112610a05576001600160401b0391600435838111610a05578261325391600401613192565b9261ffff6024358181168103610a0557936001600160a01b03906044358281168103610a05579460643594608435818111610a05578361329591600401613192565b9460a4359081168103610a05579360c4359081168103610a05579260e435918211610a05576132c69160040161305d565b9091565b90600182811c921680156132fa575b60208310146132e457565b634e487b7160e01b600052602260045260246000fd5b91607f16916132d9565b9060405191826000825492613318846132ca565b9081845260019485811690816000146133875750600114613344575b50506133429250038361311f565b565b9093915060005260209081600020936000915b81831061336f57505061334293508201013880613334565b85548884018501529485019487945091830191613357565b91505061334294506020925060ff191682840152151560051b8201013880613334565b60005b8381106133bd5750506000910152565b81810151838201526020016133ad565b906020916133e6815180928185528580860191016133aa565b601f01601f1916010190565b6080600319820112610a05576004356001600160a01b0381168103610a05579160243591604435906001600160401b038211610a055761343491600401613192565b9060643561ffff81168103610a055790565b6040600319820112610a0557600435906001600160401b038211610a055761347091600401613192565b9060243590565b906060600319830112610a055760043591602435906001600160401b038211610a05576134a691600401613192565b9060443561ffff81168103610a055790565b906040600319830112610a055760043563ffffffff81168103610a055791602435906001600160401b038211610a05576132c69160040161305d565b60043563ffffffff81168103610a055790565b63ffffffff16806000526003602052604060002054908115613527575090565b6024906040519063f6ff4fb760e01b82526004820152fd5b6002546001600160a01b0316330361355357565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b9081526001600160a01b0390911660208201526060604082018190526131ad929101906133cd565b6002600454146135d0576002600455565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815261334291613657826130b3565b60018060a01b0316906136b660405161366f816130ce565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af16136b061374c565b9161377c565b805191821591848315613728575b5050509050156136d15750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b919381809450010312610d1f5782015190811515820361032a5750803880846136c4565b3d15613777573d9061375d82613140565b9161376b604051938461311f565b82523d6000602084013e565b606090565b919290156137de5750815115613790575090565b3b156137995790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156137f15750805190602001fd5b60405162461bcd60e51b815260206004820152908190612f049060248301906133cd565b9190820180921161382257565b634e487b7160e01b600052601160045260246000fd5b91939261ffff906138536040936060865260608601906133cd565b95602085015216910152565b9190820391821161382257565b9691936138936138c79560e098939b9a9b9795978a526101008060208c01528a01906133cd565b61ffff96871660408a01526001600160a01b0391821660608a01529316608088015260a087015285820360c08701526133cd565b9416910152565b60405163a9059cbb60e01b60208201526001600160a01b039290921660248301526044808301939093529181526133429161365760648361311f565b6139a8939291604091829161394883519160009687602085015230868501523060608501528760808501528760a085015260a08452611ef684613104565b908560208551613957816130ce565b828152015261396583613507565b63ffffffff855194613976866130b3565b1684526020840152838301526060820152836080820152815180968192631bb8518b60e31b8352309060048401613a61565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa938415613a2e5782946139f1575b5050506020825192015190565b90809294503d8311613a27575b613a08818361311f565b8101918183031261127057613a1e929350613a39565b903880806139e4565b503d6139fe565b5051903d90823e3d90fd5b9190826040910312610a0557604051613a51816130ce565b6020808294805184520151910152565b906020909392936040835263ffffffff81511660408401528181015160608401526080613ab5613a9f604084015160a08488015260e08701906133cd565b6060840151868203603f190160a08801526133cd565b910151151560c08401526001600160a01b03909416910152565b959796929460e095613af6613b1a9461ffff97948a526101008060208c01528a01906133cd565b6001600160a01b0391821660408a01529216606088015286820360808801526133cd565b9560a0850152600060c085015216910152565b959091929660018060a01b0388161561115157613c629160809163ffffffff8516600052601260205260406000209860018060a01b031698896000526020526040600020613b7c878254613815565b9055604051916000602084015289604084015260018060a01b038b166060840152868484015261ffff891660a084015260a08352613bb983613104565b60405192613bc6846130ce565b888452602084019360008552604051613bde816130e9565b60008152600060208201526040805191613bf7836130ce565b600083526000602084015201525192613c0f88613507565b945115159160405195613c21876130b3565b63ffffffff8a168752602087015260408601526060850152848401526040518095819482936302637a4560e41b845260018060a01b03169060048401613a61565b03917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015613da657613cff575b509160e09493917f165b3c04a9c8fc9c822a44f0d840f61c6fb09632ee91b3ea8bcf828dc4d8123f9663ffffffff61ffff9560405197885216602087015233604087015260018060a01b03166060860152608085015260a08401521660c0820152a1565b929094939160803d608011613d9f575b613d19818661311f565b840196608085890312610a055760405197613d33896130e9565b855189526020860151976001600160401b0389168903610a0557896040613d8e63ffffffff948261ffff9b7f165b3c04a9c8fc9c822a44f0d840f61c6fb09632ee91b3ea8bcf828dc4d8123f9f9e60e09f6020015201613a39565b910152939550509650919394613c9b565b503d613d0f565b6040513d6000823e3d90fd5b96929461ffff95613dda613dfe9460e0999c9b97948b526101008060208d01528b01906133cd565b6001600160a01b0391821660408b01529216606089015287820360808901526133cd565b9660a086015260c085015216910152565b939490929194825115611151577faa37b49eafeac48f132d97d137275bc85ff34a908842ef8315c476099c39268f95613e749360018060a01b03861660005260136020526040600020613e63838254613815565b905560405196879633914689613db2565b0390a1565b939490929194825115611151577fc95a75fe1f519ea51604d41bd3d4344af8fbe2f375cd0c7a8e14d17e24bea71895613e749360018060a01b03861660005260146020526040600020613e63838254613815565b8181029291811591840414171561382257565b613f1760018060a01b0391613f11613f0b613f018560075460081c16613fca565b9460085416613fca565b93613f64565b90613ecd565b60ff600c541690604d821161382257613f3c6305f5e10091613f4393600a0a90613ecd565b0491613f64565b908115613f4e570490565b634e487b7160e01b600052601260045260246000fd5b60008112613f6f5790565b606460405162461bcd60e51b815260206004820152602060248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152fd5b519069ffffffffffffffffffff82168203610a0557565b604051633fabe5a360e21b81529060a090829060049082906001600160a01b03165afa908115613da657600091613fff575090565b9060a0823d8211614040575b8161401860a0938361311f565b8101031261032a575061402a81613fb3565b5061403c608060208301519201613fb3565b5090565b3d915061400b565b6000546001600160a01b0316330361405c57565b60405162469b1b60e21b8152600490fd5b6001546001600160a01b0316330361408157565b60405163e71a631f60e01b8152600490fdfea264697066735822122057bfd7958c2385a161b139c06a29b4841dd18761b0d0381372d400a8f75d794c64736f6c634300081400330000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f9000000000000000000000000117befc485f6d2806abf13ad878588393a2ef82b0000000000000000000000006edce65403992e310a62460808c4b910d972f10f000000000000000000000000b6a2e5c473f48142a7f2143bac4a4744635d1fe1000000000000000000000000b6a2e5c473f48142a7f2143bac4a4744635d1fe1000000000000000000000000b6a2e5c473f48142a7f2143bac4a4744635d1fe10000000000000000000000001b44f3514812d835eb1bdb0acb33d3fa3351ee43000000000000000000000000694aa1769357215de4fac081bf1f309adc3253060000000000000000000000000000000000000000000000000000000000000012
Deployed Bytecode
0x6080604052600436101561001b575b361561001957600080fd5b005b6000803560e01c80630a1cdedd14612f8d5780630c6dd9fd14612f2057806313137d651461285357806317442b70146128315780631ffcdacc1461280857806329575f6a146127e157806330049a99146125b85780633400288b146125435780633456681f1461250a57806338e298441461227d5780633aab16bf146122425780633f7edb01146121a15780633f8976e714612100578063403f203914611ff15780634162b79714611fb857806344a59e7a14611f9757806346f6f9b514611f7b5780634b77fd8c14611f195780634da50b9b14611e065780635e280f1114611dc15780635fcf695414611cca57806360893a6414611c8b57806361a552dc14611c6857806366ab147014611a1957806368ea28b0146119fd57806369a6b3db1461199957806369fe0e2d1461194e578063715018a6146119325780637d25a05e1461190c578063801e27aa146118ee57806382413eac1461189557806382f81e2c1461187757806384abb7ad1461180e578063879bd5b11461170d5780638b762d5e146116bf5780638cf39750146112dc5780638da5cb5b146112b35780639ac46b0c146112935780639fa18e7314611179578063a0d300db14610e6c578063a34195de14610e4b578063aa293c6814610df8578063aaa2565714610da5578063ab11c84b14610d7c578063ad38983614610bbe578063ad5c464814610b79578063b7b91f4814610b34578063bb0b6a5314610aff578063c5e1669714610acb578063c663f8bc14610aad578063ca5eb5e114610a0a578063cb8d3b1f14610981578063cea9d26f146108e2578063d333555314610855578063d4c1de9614610769578063d683047314610700578063ddca3f43146106e2578063e325c1021461065f578063e3ea50e614610638578063e8a77319146105ea578063ed79444814610489578063ee7a45961461044a578063f2fde38b14610385578063f5d328521461032d5763ff7bd03d146102f2575061000e565b3461032a57606036600319011261032a57604060209163ffffffff6103156134f4565b16815260038352205460405190602435148152f35b80fd5b503461032a57604036600319011261032a5760406103496131ef565b9163ffffffff610357613033565b93168152600d602052209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b503461032a57602036600319011261032a5761039f612fdb565b6103a761353f565b6001600160a01b039081169081156103f657600254826001600160601b0360a01b821617600255167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b503461032a57602036600319011261032a5760209060ff906040906001600160a01b03610475612fdb565b168152600584522054166040519015158152f35b503461032a5761049836613446565b906104a161406d565b604051908051916020926104b881838686016133aa565b600f90820190815281900383019020546001600160a01b03169182156105d85760ff6007541680156105c3575b6105b15782855260138152604085205484811061059f57846105069161385f565b8386526013825260408620556010815261052260408620613304565b511561058d577f6b39fd225531170ecf6b0e90d2dd9aea69d840f4ad8386607d6d796caedc9248938361058394875260148352610563826040892054613815565b9087526014835260408720556040519384936040855260408501906133cd565b918301520390a180f35b60405163dd4fba9d60e01b8152600490fd5b60405163bb55fd2760e01b8152600490fd5b6040516313d0ff5960e31b8152600490fd5b508285526005815260ff6040862054166104e5565b604051636836902f60e01b8152600490fd5b503461032a57602036600319011261032a577fd18deff1242be1004442079420ded12d884c5acb1d5645366eb935a1a137e3ce602060043561062a61353f565b80600b55604051908152a180f35b503461032a57602036600319011261032a576020610657600435613ee0565b604051908152f35b503461032a57602036600319011261032a57610679612fdb565b61068161406d565b6001600160a01b039081169081156106d057600154826001600160601b0360a01b821617600155167ffe89f6b8b3c79299e51301ea59956d9f4f6c40a14c27dc1bb6f4de8511fe80c48380a380f35b60405163d92e233d60e01b8152600490fd5b503461032a578060031936011261032a576020601654604051908152f35b503461032a57602036600319011261032a57600435906001600160401b03821161032a5760206107333660048501613192565b8161074760405192838151938492016133aa565b600f90820190815281900382019020546040516001600160a01b039091168152f35b503461032a57604036600319011261032a57610783612fdb565b61078b613202565b9061079461353f565b6001600160a01b03169081156108435763ffffffff1690818352602090600d82526040842081600052825260ff6040600020541661083157826040927fabe08574bb9012ad7bf75950900dba182a5acc179e7dff4f1419d9c7dd292e07948652600d81528386208360005281528360002060ff1990600182825416179055838752600682526001858820918254161790558351928352820152a180f35b604051630aca00b560e41b8152600490fd5b604051630f58058360e11b8152600490fd5b503461032a57602036600319011261032a57600435610872614048565b4781116108d0578180808084335af161088961374c565b50156108be576040519081527f998c1d4558d59dad65b19a98dc38b7be7da91872c437602b882f3fe9b012af1660203392a280f35b604051632245761f60e11b8152600490fd5b60405163162908e360e11b8152600490fd5b503461032a57606036600319011261032a576108fc612fdb565b610904613033565b9060443590610911614048565b6001600160a01b039081168085526006602052604085205490939060ff1661096f577f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb918161096385602094886138ce565b6040519485521692a380f35b6040516364c6c5af60e11b8152600490fd5b503461032a57604036600319011261032a5761099b612fdb565b60243590811515809203610a05577fb1656bd3b50ddb6b12ef259c86e9cb359952b53c4403cfb5a83e23c515a35e22916040916109d661353f565b60018060a01b031690818552600560205282852060ff1981541660ff831617905582519182526020820152a180f35b600080fd5b503461032a57602036600319011261032a5780610a25612fdb565b610a2d61353f565b6001600160a01b037f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f81169190823b15610aa8576024849283604051958694859363ca5eb5e160e01b85521660048401525af18015610a9d57610a8d5750f35b610a969061308a565b61032a5780f35b6040513d84823e3d90fd5b505050fd5b503461032a578060031936011261032a576020600b54604051908152f35b503461032a576040610ae5610adf366134b8565b9161390a565b50610af281601654613815565b9082519182526020820152f35b503461032a57602036600319011261032a57604060209163ffffffff610b236131ef565b168152600383522054604051908152f35b503461032a578060031936011261032a576040517f000000000000000000000000117befc485f6d2806abf13ad878588393a2ef82b6001600160a01b03168152602090f35b503461032a578060031936011261032a576040517f0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f96001600160a01b03168152602090f35b5060c036600319011261032a57610bd36131ef565b60243590610bdf61301d565b60643561ffff81168103610a0557610bf5613007565b60a4356001600160401b038111610d7857610c1490369060040161305d565b9390957f0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f99560ff600754168015610d59575b6105b157610c526135bf565b63ffffffff81168952600d602052604089209360018060a01b0390818916958660005260205260ff6040600020541615610d475783156108d05716958615610d3557610c9f818a8461390a565b5094610cb684610cb188601654613815565b613815565b3410610d2357808b913b15610d1f57818591600460405180948193630d0e30db60e41b83525af18015610a9d57610d07575b5050610cff98610cf991369161315b565b96613b2d565b600160045580f35b610d109061308a565b610d1b578938610ce8565b8980fd5b5080fd5b60405163a5fb6be960e01b8152600490fd5b60405163717f139360e11b8152600490fd5b60405163350b944160e11b8152600490fd5b506001600160a01b03871689526005602052604089205460ff16610c46565b8680fd5b503461032a578060031936011261032a576020610657610d9d600954613ee0565b601654613815565b503461032a57602036600319011261032a57610df490610de0906040906001600160a01b03610dd2612fdb565b168152601060205220613304565b6040519182916020835260208301906133cd565b0390f35b503461032a57604036600319011261032a576040610e146131ef565b9163ffffffff610e22613033565b931681526012602052209060018060a01b03166000526020526020604060002054604051908152f35b503461032a578060031936011261032a576020610657610d9d600b54613ee0565b50610e7636613226565b610e8798969195929894939461406d565b6040518751610e9a818360208c016133aa565b600f9082019081528190036020019020546001600160a01b03169081156105d85760ff600754168015611163575b6105b1576001600160a01b038316156111515783156108d05784511561113f5760ff6040516020818851610eff8183858d016133aa565b81016015815203019020541661112d576040516020818751610f248183858c016133aa565b81016015815203019020600160ff19825416179055818b52601360205260408b205484811061059f5784610f579161385f565b828c52601360205260408c205561ffff8916998a15611017578a8c52600d60205260408c208360005260205260ff6040600020541615610d47576001600160a01b0316998a15610d3557610fac82898361390a565b503410611006577f9deadd1c613e22cde00a3cd2e97e3188edcf234e9f019a736b4812e2c1591a8c9a87610fe86110009a610ff395369161315b565b928688349288613b2d565b604051978897468961386c565b0390a180f35b60405162976f7560e21b8152600490fd5b5091985094508890507f0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f96001600160a01b03168086036110f557803b15610d1f57818091602460405180948193632e1a7d4d60e01b83528860048401525af18015610a9d576110dd575b50808080846001600160a01b038c165af161109a61374c565b50156110cb577f9deadd1c613e22cde00a3cd2e97e3188edcf234e9f019a736b4812e2c1591a8c9661100094610ff3565b6040516364eefe4560e01b8152600490fd5b6110e69061308a565b6110f1578738611081565b8780fd5b50508684611128837f9deadd1c613e22cde00a3cd2e97e3188edcf234e9f019a736b4812e2c1591a8c9a611000986138ce565b610ff3565b604051637b7d123560e11b8152600490fd5b604051635d4e0b5360e01b8152600490fd5b604051630521f43160e31b8152600490fd5b50818b52600560205260ff60408c205416610ec8565b5061118336613477565b91907f000000000000000000000000117befc485f6d2806abf13ad878588393a2ef82b60ff600754168015611274575b6105b15782156108d057815115611151576111d2610d9d600b54613ee0565b34106110065784906001600160a01b03166111ef84303384613615565b803b15610d1f57604051632770a7eb60e21b8152306004820152602481018590529082908290604490829084905af18015610a9d5761125c575b50506110007f0146b632afdb6e46c1215c95eb6b39d9f439e67b687d7d499bd6a0441c5735909360405193849384613838565b6112659061308a565b611270578338611229565b8380fd5b506001600160a01b03811685526005602052604085205460ff166111b3565b503461032a5760406112a7610adf366134b8565b82519182526020820152f35b503461032a578060031936011261032a576002546040516001600160a01b039091168152602090f35b5060e036600319011261032a576001600160401b036004358181116116bb57611309903690600401613192565b611311613202565b61131961301d565b92611322613215565b9061132b612ff1565b9060c435908111610d785761134490369060040161305d565b60ff60075416801561167c575b6105b15761135d61406d565b6001600160a01b0387161561115157606435156108d05785511561113f5760405160ff875191602081818b01946113958183886133aa565b81016015815203019020541661166a5760206113bc91604051809381928b519283916133aa565b81016015815203019020600160ff1982541617905563ffffffff8516156000146114e15750869150507f000000000000000000000000117befc485f6d2806abf13ad878588393a2ef82b6001600160a01b0316803b15610d1f576040516340c10f1960e01b81526001600160a01b038716600482015260643560248201529082908290604490829084905af18015610a9d576114c3575b50509061ffff61149a93927f58c5f63c547f733187f13f3945ac85668fc5dfc499a92668068ab4d96f7ea240955b63ffffffff60405196879660a0885260a08801906133cd565b941660208601526001600160a01b0316604085015260643560608501521660808301520390a180f35b6114d0909493929461308a565b6114dd5790918438611453565b8480fd5b63ffffffff85979495168852600d6020526040882060018060a01b037f000000000000000000000000117befc485f6d2806abf13ad878588393a2ef82b1660005260205260ff6040600020541615610d475761153e81838961390a565b503410611006577f000000000000000000000000117befc485f6d2806abf13ad878588393a2ef82b6001600160a01b03163b156110f1576040516340c10f1960e01b8152306004820152606435602482015288908181604481836001600160a01b037f000000000000000000000000117befc485f6d2806abf13ad878588393a2ef82b165af18015610a9d57611648575b50509261164361ffff9361160c61149a9897947f58c5f63c547f733187f13f3945ac85668fc5dfc499a92668068ab4d96f7ea2409a97369161315b565b906001600160a01b03168434856064358a7f000000000000000000000000117befc485f6d2806abf13ad878588393a2ef82b613b2d565b611481565b61165990989592949796939861308a565b6110f15792959093949187386115cf565b6040516304f78f7d60e41b8152600490fd5b507f000000000000000000000000117befc485f6d2806abf13ad878588393a2ef82b6001600160a01b031688526005602052604088205460ff16611351565b8280fd5b503461032a57602036600319011261032a577f371575ff48070c3a186a41fa4a051e9bd9695cc6d58b4c13791e366913ec8c7860206004356116ff61353f565b80600a55604051908152a180f35b5061171736613477565b90917f0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f99260ff6007541680156117ef575b6105b1576117546135bf565b6001600160a01b038416808652600e6020526040862061177390613304565b90815115610d475783156108d057611798611792610d9d600954613ee0565b85613815565b3410610d23578087913b15610d1f57818591600460405180948193630d0e30db60e41b83525af18015610a9d576117d7575b5050610cff948391613e0f565b6117e09061308a565b6117eb5785386117ca565b8580fd5b506001600160a01b03841685526005602052604085205460ff16611748565b503461032a57602036600319011261032a57600435906001600160401b03821161032a5760206118413660048501613192565b8161185560405192838151938492016133aa565b601190820190815281900382019020546040516001600160a01b039091168152f35b503461032a578060031936011261032a576020600a54604051908152f35b503461032a57366003190160a08112610d1f5760601361032a576064356001600160401b038111610d1f576118ce90369060040161305d565b505060206118da613007565b6040516001600160a01b0390911630148152f35b503461032a578060031936011261032a576020600954604051908152f35b503461032a57604036600319011261032a576020906119296131ef565b50604051908152f35b503461032a578060031936011261032a5761194b61353f565b80f35b503461032a57602036600319011261032a5760043561196b61353f565b806016547f5fc463da23c1b063e66f9e352006a7fbe8db7223c455dc429e881a2dfe2f94f18480a360165580f35b503461032a57602036600319011261032a57600435801515809103610a055760207f5362d4bd13945e8d116b90d83a7050fa61ceb02bb79bfae783377adb46916d94916119e461353f565b60ff196007541660ff821617600755604051908152a180f35b503461032a578060031936011261032a57602060405160018152f35b503461032a57611a28366131b0565b611a3392919261353f565b6001600160a01b0392808416801561084357825115611c5657808452602094600e8652611a6360408620546132ca565b1590811591611c2c575b5061083157808452600e85526040842083516001600160401b038111611c1857611a9782546132ca565b601f8111611bd5575b5086601f8211600114611b4f579181600694928899947f0fb40cd98da6acecd96260ef53ad7139c1f4d565241278a46ece82fbdae6fc979991611b44575b508160011b916000199060031b1c19161790555b60405182818751611b068183858c016133aa565b8101600f815203019020816001600160601b0360a01b82541617905586525260408420600160ff198254161790556110006040519283924684613597565b905087015138611ade565b82875287872090601f198316885b818110611bbe5750927f0fb40cd98da6acecd96260ef53ad7139c1f4d565241278a46ece82fbdae6fc9798999492600192826006989610611ba5575b5050811b019055611af2565b89015160001960f88460031b161c191690553880611b99565b91928a60018192868c015181550194019201611b5d565b828752878720601f830160051c810191898410611c0e575b601f0160051c01905b818110611c035750611aa0565b878155600101611bf6565b9091508190611bed565b634e487b7160e01b86526041600452602486fd5b905060405186818651611c428183858b016133aa565b8101600f8152030190205416151538611a6d565b6040516333a3bdff60e21b8152600490fd5b503461032a578060031936011261032a57602060ff600754166040519015158152f35b503461032a57602036600319011261032a5760209060ff906040906001600160a01b03611cb6612fdb565b168152600684522054166040519015158152f35b50611cd436613477565b90917f0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f99260ff600754168015611da2575b6105b157611d116135bf565b6001600160a01b038416808652601060205260408620611d3090613304565b90815115610d475783156108d057611d4f611792610d9d600a54613ee0565b3410610d23578087913b15610d1f57818591600460405180948193630d0e30db60e41b83525af18015610a9d57611d8e575b5050610cff948391613e79565b611d979061308a565b6117eb578538611d81565b506001600160a01b03841685526005602052604085205460ff16611d05565b503461032a578060031936011261032a576040517f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f6001600160a01b03168152602090f35b5060e036600319011261032a57611e1b612fdb565b611e23613202565b906001600160a01b036064356044358282168203610a0557611e43613215565b91611e4c612ff1565b9160c4356001600160401b038111611f1557611e6c90369060040161305d565b97909560ff600754168015611efd575b6105b157611e886135bf565b63ffffffff82168a52600d60205260408a2090808916918260005260205260ff6040600020541615610d475783156108d057611ec58a898561390a565b5095611ed387601654613815565b34106110065716968715610d3557610cff99611ef685610cf99430903390613615565b369161315b565b508088168a52600560205260ff60408b205416611e7c565b8880fd5b503461032a57602036600319011261032a57600435906001600160401b03821161032a57602060ff611f6582611f523660048801613192565b81604051938285809451938492016133aa565b8101601581520301902054166040519015158152f35b503461032a578060031936011261032a57602090604051908152f35b503461032a578060031936011261032a576020610657610d9d600a54613ee0565b503461032a57602036600319011261032a576020906040906001600160a01b03611fe0612fdb565b168152601483522054604051908152f35b503461032a5761200036613446565b9061200961406d565b6040519080519160209261202081838686016133aa565b601190820190815281900383019020546001600160a01b031691821561058d5760ff6007541680156120eb575b6105b15782855260148152604085205484811061059f578461206e9161385f565b838652601482526040862055600e815261208a60408620613304565b51156105d8577fa75e52d94defea74c89d66fabe973e2d214241c54756b59e2ae5b301b4dbdba49383610583948752601383526120cb826040892054613815565b9087526013835260408720556040519384936040855260408501906133cd565b508285526005815260ff60408620541661204d565b5061210a366133f2565b91929060ff600754168015612182575b6105b1576121266135bf565b6001600160a01b038216808652600e6020526040862090949061214890613304565b92835115610d475781156108d057612164610d9d600954613ee0565b34106110065761217b82610cff9730903390613615565b3493613e0f565b506001600160a01b03821685526005602052604085205460ff1661211a565b506121ab366133f2565b91929060ff600754168015612223575b6105b1576121c76135bf565b6001600160a01b0382168086526010602052604086209094906121e990613304565b92835115610d475781156108d057612205610d9d600a54613ee0565b34106110065761221c82610cff9730903390613615565b3493613e79565b506001600160a01b03821685526005602052604085205460ff166121bb565b503461032a57602036600319011261032a57610df490610de0906040906001600160a01b0361226f612fdb565b168152600e60205220613304565b5061228736613226565b61229898969195929894939461406d565b60405187516122ab818360208c016133aa565b60119082019081528190036020019020546001600160a01b031690811561058d5760ff6007541680156124f4575b6105b1576001600160a01b038316156111515783156108d05784511561113f5760ff60405160208188516123108183858d016133aa565b81016015815203019020541661112d5760405160208187516123358183858c016133aa565b81016015815203019020600160ff19825416179055818b52601460205260408b205484811061059f57846123689161385f565b828c52601460205260408c205561ffff8916998a156123f9578a8c52600d60205260408c208360005260205260ff6040600020541615610d47576001600160a01b0316998a15610d35576123bd82898361390a565b503410611006577f335053ef368b8e10c38ca548e91f7fd4dd09802d68e273c2c94f60bcb302c3ef9a87610fe86110009a610ff395369161315b565b5091985094508890507f0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f96001600160a01b03168086036124c157803b15610d1f57818091602460405180948193632e1a7d4d60e01b83528860048401525af18015610a9d576124ad575b50808080846001600160a01b038c165af161247c61374c565b50156110cb577f335053ef368b8e10c38ca548e91f7fd4dd09802d68e273c2c94f60bcb302c3ef9661100094610ff3565b6124b69061308a565b6110f1578738612463565b50508684611128837f335053ef368b8e10c38ca548e91f7fd4dd09802d68e273c2c94f60bcb302c3ef9a611000986138ce565b50818b52600560205260ff60408c2054166122d9565b503461032a57602036600319011261032a576020906040906001600160a01b03612532612fdb565b168152601383522054604051908152f35b503461032a57604036600319011261032a577f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b61257e6131ef565b6024359061258a61353f565b63ffffffff168084526003602090815260408086208490558051928352908201929092529081908101611000565b503461032a576125c7366131b0565b6125d292919261353f565b6001600160a01b0392808416801561084357825115611c56578084526020946010865261260260408620546132ca565b15908115916127b7575b5061083157808452601085526040842083516001600160401b038111611c185761263682546132ca565b601f8111612774575b5086601f82116001146126ee579181600694928899947fff3862ec7ba8a30d15808fdfff5539e5492b1af4fb550d9ee24d5a5958b7a05499916126e3575b508160011b916000199060031b1c19161790555b604051828187516126a58183858c016133aa565b81016011815203019020816001600160601b0360a01b82541617905586525260408420600160ff198254161790556110006040519283924684613597565b90508701513861267d565b82875287872090601f198316885b81811061275d5750927fff3862ec7ba8a30d15808fdfff5539e5492b1af4fb550d9ee24d5a5958b7a05498999492600192826006989610612744575b5050811b019055612691565b89015160001960f88460031b161c191690553880612738565b91928a60018192868c0151815501940192016126fc565b828752878720601f830160051c8101918984106127ad575b601f0160051c01905b8181106127a2575061263f565b878155600101612795565b909150819061278c565b9050604051868186516127cd8183858b016133aa565b81016011815203019020541615153861260c565b503461032a578060031936011261032a57546040516001600160a01b039091168152602090f35b503461032a578060031936011261032a576001546040516001600160a01b039091168152602090f35b503461032a578060031936011261032a57604080516001815260026020820152f35b50366003190160e08112610d1f5760601361032a576001600160401b036084358181116116bb5761288890369060040161305d565b612890612ff1565b5060c4358381116114dd576128a990369060040161305d565b5050337f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f6001600160a01b031603612f08576128eb6128e66134f4565b613507565b602435809103612ed457506128fe6134f4565b90820192610100838503126114dd5782359160ff831683036117eb5761292660208501613049565b9361293360408201613049565b926003608083013510159687611f155760a0830135918211611f155761295a918301613192565b9260c08201359461ffff86168603611f155760e08301358015159003611f155760ff600754168015612eb5575b6105b15760ff6001911603612ea35763ffffffff83168852600d60209081526040808a206001600160a01b0389168b5290915288205460ff1615610d475760e08201358015612e92575b878115612e7e575b5015612e5e57835115612e4c575b63ffffffff83168852601260209081526040808a206001600160a01b0389168b529091528820546060830135979088811061059f5788612a269161385f565b63ffffffff85168a52601260209081526040808c206001600160a01b038b168d529091528a2055612e38576080820135600103612ae6575050506001600160a01b0383168552600e60205260408520612a7e90613304565b918251156105d8577faa37b49eafeac48f132d97d137275bc85ff34a908842ef8315c476099c39268f946110009260018060a01b0386168852601360205260408820612acb838254613815565b905560405195869533916001600160a01b0316904688613acf565b6080820135600203612b60575050506001600160a01b0383168552601060205260408520612b1390613304565b9182511561058d577fc95a75fe1f519ea51604d41bd3d4344af8fbe2f375cd0c7a8e14d17e24bea718946110009260018060a01b0386168852601460205260408820612acb838254613815565b909193929594608083013515612b7b575b5050505050505080f35b6001600160a01b037f0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f98116919081168203612c9457508088913b15610d1f57818091602460405180948193632e1a7d4d60e01b83528c60048401525af18015610a9d57612c80575b50506001600160a01b0316938680808084895af1612bff61374c565b50156110cb577f56e20f170e9c90c8d90b8c5cd4d1e164c2566c12df53734662f03d00003fe95795608061ffff93612c699363ffffffff98604051998a9960008b521660208a0152604089015260608801520135608086015260e060a086015260e08501906133cd565b911660c08301520390a15b38808080808080612b71565b612c899061308a565b610d78578638612be3565b939796946001600160a01b037f000000000000000000000000117befc485f6d2806abf13ad878588393a2ef82b811695919491939192508316851480612e2d575b15612d935750505050803b1561127057604051632770a7eb60e21b8152306004820152602481018490529084908290604490829084905af18015612d8857612d53575b50612d4b7f0146b632afdb6e46c1215c95eb6b39d9f439e67b687d7d499bd6a0441c573590939460405193849384613838565b0390a1612c74565b7f0146b632afdb6e46c1215c95eb6b39d9f439e67b687d7d499bd6a0441c57359093612d81612d4b9261308a565b9350612d18565b6040513d86823e3d90fd5b7f56e20f170e9c90c8d90b8c5cd4d1e164c2566c12df53734662f03d00003fe95797989450612e1e92959161ffff949760809260018060a01b0316612de1828260018060a01b038c166138ce565b63ffffffff6040519a8b9a60018060a01b03168b521660208a0152604089015260608801520135608086015260e060a086015260e08501906133cd565b911660c08301520390a1612c74565b5060e0820135612cd5565b634e487b7160e01b88526021600452602488fd5b60405163ecd987b560e01b8152600490fd5b6001600160a01b0381166129e757604051630521f43160e31b8152600490fd5b9050612e38576002608083013514876129d9565b5087965060808201356001146129d1565b60405163fe3e832760e01b8152600490fd5b506001600160a01b03871689526005602052604089205460ff16612987565b612edc6134f4565b60405163309afaf360e21b815263ffffffff9190911660048201526024810191909152604490fd5b0390fd5b6040516391ac5e4f60e01b8152336004820152602490fd5b503461032a57602036600319011261032a57612f3a612fdb565b612f42614048565b6001600160a01b039081169081156106d05782546001600160a01b0319811683178455167f0f62530a074f4e1e883a8c916fa7f8639d52598edb7f9b5aa3148d991db5610d8380a380f35b503461032a57602036600319011261032a577f660ff051b38f76351c8ee1877577ca6b1f289c7b967cc2d2d657eb9561eefafd6020600435612fcd61353f565b80600955604051908152a180f35b600435906001600160a01b0382168203610a0557565b60a435906001600160a01b0382168203610a0557565b608435906001600160a01b0382168203610a0557565b604435906001600160a01b0382168203610a0557565b602435906001600160a01b0382168203610a0557565b35906001600160a01b0382168203610a0557565b9181601f84011215610a05578235916001600160401b038311610a055760208381860195010111610a0557565b6001600160401b03811161309d57604052565b634e487b7160e01b600052604160045260246000fd5b60a081019081106001600160401b0382111761309d57604052565b604081019081106001600160401b0382111761309d57604052565b606081019081106001600160401b0382111761309d57604052565b60c081019081106001600160401b0382111761309d57604052565b90601f801991011681019081106001600160401b0382111761309d57604052565b6001600160401b03811161309d57601f01601f191660200190565b92919261316782613140565b91613175604051938461311f565b829481845281830111610a05578281602093846000960137010152565b9080601f83011215610a05578160206131ad9335910161315b565b90565b906040600319830112610a05576004356001600160a01b0381168103610a055791602435906001600160401b038211610a05576131ad91600401613192565b6004359063ffffffff82168203610a0557565b6024359063ffffffff82168203610a0557565b6084359061ffff82168203610a0557565b610100600319820112610a05576001600160401b0391600435838111610a05578261325391600401613192565b9261ffff6024358181168103610a0557936001600160a01b03906044358281168103610a05579460643594608435818111610a05578361329591600401613192565b9460a4359081168103610a05579360c4359081168103610a05579260e435918211610a05576132c69160040161305d565b9091565b90600182811c921680156132fa575b60208310146132e457565b634e487b7160e01b600052602260045260246000fd5b91607f16916132d9565b9060405191826000825492613318846132ca565b9081845260019485811690816000146133875750600114613344575b50506133429250038361311f565b565b9093915060005260209081600020936000915b81831061336f57505061334293508201013880613334565b85548884018501529485019487945091830191613357565b91505061334294506020925060ff191682840152151560051b8201013880613334565b60005b8381106133bd5750506000910152565b81810151838201526020016133ad565b906020916133e6815180928185528580860191016133aa565b601f01601f1916010190565b6080600319820112610a05576004356001600160a01b0381168103610a05579160243591604435906001600160401b038211610a055761343491600401613192565b9060643561ffff81168103610a055790565b6040600319820112610a0557600435906001600160401b038211610a055761347091600401613192565b9060243590565b906060600319830112610a055760043591602435906001600160401b038211610a05576134a691600401613192565b9060443561ffff81168103610a055790565b906040600319830112610a055760043563ffffffff81168103610a055791602435906001600160401b038211610a05576132c69160040161305d565b60043563ffffffff81168103610a055790565b63ffffffff16806000526003602052604060002054908115613527575090565b6024906040519063f6ff4fb760e01b82526004820152fd5b6002546001600160a01b0316330361355357565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b9081526001600160a01b0390911660208201526060604082018190526131ad929101906133cd565b6002600454146135d0576002600455565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815261334291613657826130b3565b60018060a01b0316906136b660405161366f816130ce565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af16136b061374c565b9161377c565b805191821591848315613728575b5050509050156136d15750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b919381809450010312610d1f5782015190811515820361032a5750803880846136c4565b3d15613777573d9061375d82613140565b9161376b604051938461311f565b82523d6000602084013e565b606090565b919290156137de5750815115613790575090565b3b156137995790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156137f15750805190602001fd5b60405162461bcd60e51b815260206004820152908190612f049060248301906133cd565b9190820180921161382257565b634e487b7160e01b600052601160045260246000fd5b91939261ffff906138536040936060865260608601906133cd565b95602085015216910152565b9190820391821161382257565b9691936138936138c79560e098939b9a9b9795978a526101008060208c01528a01906133cd565b61ffff96871660408a01526001600160a01b0391821660608a01529316608088015260a087015285820360c08701526133cd565b9416910152565b60405163a9059cbb60e01b60208201526001600160a01b039290921660248301526044808301939093529181526133429161365760648361311f565b6139a8939291604091829161394883519160009687602085015230868501523060608501528760808501528760a085015260a08452611ef684613104565b908560208551613957816130ce565b828152015261396583613507565b63ffffffff855194613976866130b3565b1684526020840152838301526060820152836080820152815180968192631bb8518b60e31b8352309060048401613a61565b03817f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f6001600160a01b03165afa938415613a2e5782946139f1575b5050506020825192015190565b90809294503d8311613a27575b613a08818361311f565b8101918183031261127057613a1e929350613a39565b903880806139e4565b503d6139fe565b5051903d90823e3d90fd5b9190826040910312610a0557604051613a51816130ce565b6020808294805184520151910152565b906020909392936040835263ffffffff81511660408401528181015160608401526080613ab5613a9f604084015160a08488015260e08701906133cd565b6060840151868203603f190160a08801526133cd565b910151151560c08401526001600160a01b03909416910152565b959796929460e095613af6613b1a9461ffff97948a526101008060208c01528a01906133cd565b6001600160a01b0391821660408a01529216606088015286820360808801526133cd565b9560a0850152600060c085015216910152565b959091929660018060a01b0388161561115157613c629160809163ffffffff8516600052601260205260406000209860018060a01b031698896000526020526040600020613b7c878254613815565b9055604051916000602084015289604084015260018060a01b038b166060840152868484015261ffff891660a084015260a08352613bb983613104565b60405192613bc6846130ce565b888452602084019360008552604051613bde816130e9565b60008152600060208201526040805191613bf7836130ce565b600083526000602084015201525192613c0f88613507565b945115159160405195613c21876130b3565b63ffffffff8a168752602087015260408601526060850152848401526040518095819482936302637a4560e41b845260018060a01b03169060048401613a61565b03917f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f6001600160a01b03165af18015613da657613cff575b509160e09493917f165b3c04a9c8fc9c822a44f0d840f61c6fb09632ee91b3ea8bcf828dc4d8123f9663ffffffff61ffff9560405197885216602087015233604087015260018060a01b03166060860152608085015260a08401521660c0820152a1565b929094939160803d608011613d9f575b613d19818661311f565b840196608085890312610a055760405197613d33896130e9565b855189526020860151976001600160401b0389168903610a0557896040613d8e63ffffffff948261ffff9b7f165b3c04a9c8fc9c822a44f0d840f61c6fb09632ee91b3ea8bcf828dc4d8123f9f9e60e09f6020015201613a39565b910152939550509650919394613c9b565b503d613d0f565b6040513d6000823e3d90fd5b96929461ffff95613dda613dfe9460e0999c9b97948b526101008060208d01528b01906133cd565b6001600160a01b0391821660408b01529216606089015287820360808901526133cd565b9660a086015260c085015216910152565b939490929194825115611151577faa37b49eafeac48f132d97d137275bc85ff34a908842ef8315c476099c39268f95613e749360018060a01b03861660005260136020526040600020613e63838254613815565b905560405196879633914689613db2565b0390a1565b939490929194825115611151577fc95a75fe1f519ea51604d41bd3d4344af8fbe2f375cd0c7a8e14d17e24bea71895613e749360018060a01b03861660005260146020526040600020613e63838254613815565b8181029291811591840414171561382257565b613f1760018060a01b0391613f11613f0b613f018560075460081c16613fca565b9460085416613fca565b93613f64565b90613ecd565b60ff600c541690604d821161382257613f3c6305f5e10091613f4393600a0a90613ecd565b0491613f64565b908115613f4e570490565b634e487b7160e01b600052601260045260246000fd5b60008112613f6f5790565b606460405162461bcd60e51b815260206004820152602060248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152fd5b519069ffffffffffffffffffff82168203610a0557565b604051633fabe5a360e21b81529060a090829060049082906001600160a01b03165afa908115613da657600091613fff575090565b9060a0823d8211614040575b8161401860a0938361311f565b8101031261032a575061402a81613fb3565b5061403c608060208301519201613fb3565b5090565b3d915061400b565b6000546001600160a01b0316330361405c57565b60405162469b1b60e21b8152600490fd5b6001546001600160a01b0316330361408157565b60405163e71a631f60e01b8152600490fdfea264697066735822122057bfd7958c2385a161b139c06a29b4841dd18761b0d0381372d400a8f75d794c64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f9000000000000000000000000117befc485f6d2806abf13ad878588393a2ef82b0000000000000000000000006edce65403992e310a62460808c4b910d972f10f000000000000000000000000b6a2e5c473f48142a7f2143bac4a4744635d1fe1000000000000000000000000b6a2e5c473f48142a7f2143bac4a4744635d1fe1000000000000000000000000b6a2e5c473f48142a7f2143bac4a4744635d1fe10000000000000000000000001b44f3514812d835eb1bdb0acb33d3fa3351ee43000000000000000000000000694aa1769357215de4fac081bf1f309adc3253060000000000000000000000000000000000000000000000000000000000000012
-----Decoded View---------------
Arg [0] : _weth (address): 0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9
Arg [1] : _bBTC (address): 0x117befc485F6D2806Abf13Ad878588393a2eF82b
Arg [2] : _endpoint (address): 0x6EDCE65403992e310A62460808c4b910D972f10f
Arg [3] : _delegate (address): 0xB6A2E5C473f48142A7F2143BAc4A4744635D1fe1
Arg [4] : _btcBridge (address): 0xB6A2E5C473f48142A7F2143BAc4A4744635D1fe1
Arg [5] : _superAdmin (address): 0xB6A2E5C473f48142A7F2143BAc4A4744635D1fe1
Arg [6] : _btcDataFeed (address): 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43
Arg [7] : _nativeDataFeed (address): 0x694AA1769357215DE4FAC081bf1f309aDC325306
Arg [8] : _nativeDecimals (uint8): 18
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 0000000000000000000000007b79995e5f793a07bc00c21412e50ecae098e7f9
Arg [1] : 000000000000000000000000117befc485f6d2806abf13ad878588393a2ef82b
Arg [2] : 0000000000000000000000006edce65403992e310a62460808c4b910d972f10f
Arg [3] : 000000000000000000000000b6a2e5c473f48142a7f2143bac4a4744635d1fe1
Arg [4] : 000000000000000000000000b6a2e5c473f48142a7f2143bac4a4744635d1fe1
Arg [5] : 000000000000000000000000b6a2e5c473f48142a7f2143bac4a4744635d1fe1
Arg [6] : 0000000000000000000000001b44f3514812d835eb1bdb0acb33d3fa3351ee43
Arg [7] : 000000000000000000000000694aa1769357215de4fac081bf1f309adc325306
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000012
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.