Overview
ETH Balance
ETH Value
$0.00Latest 1 from a total of 1 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Resend Transfer | 37699562 | 11 days ago | IN | 0.000005 ETH | 0 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 38649132 | 1 hr ago | 0.000005 ETH | ||||
| 38649132 | 1 hr ago | 0.000005 ETH | ||||
| 38648925 | 1 hr ago | 0.000005 ETH | ||||
| 38648925 | 1 hr ago | 0.000005 ETH | ||||
| 38648733 | 1 hr ago | 0.000005 ETH | ||||
| 38648733 | 1 hr ago | 0.000005 ETH | ||||
| 38597490 | 15 hrs ago | 0.000005 ETH | ||||
| 38597490 | 15 hrs ago | 0.000005 ETH | ||||
| 38596907 | 15 hrs ago | 0.000005 ETH | ||||
| 38596907 | 15 hrs ago | 0.000005 ETH | ||||
| 38595462 | 15 hrs ago | 0.000005 ETH | ||||
| 38595462 | 15 hrs ago | 0.000005 ETH | ||||
| 38595343 | 15 hrs ago | 0.000005 ETH | ||||
| 38595343 | 15 hrs ago | 0.000005 ETH | ||||
| 38544299 | 30 hrs ago | 0.000005 ETH | ||||
| 38544299 | 30 hrs ago | 0.000005 ETH | ||||
| 38543438 | 30 hrs ago | 0.000005 ETH | ||||
| 38543438 | 30 hrs ago | 0.000005 ETH | ||||
| 38535444 | 32 hrs ago | 0.000005 ETH | ||||
| 38535444 | 32 hrs ago | 0.000005 ETH | ||||
| 38483227 | 47 hrs ago | 0.000005 ETH | ||||
| 38483227 | 47 hrs ago | 0.000005 ETH | ||||
| 38483103 | 47 hrs ago | 0.000005 ETH | ||||
| 38483103 | 47 hrs ago | 0.000005 ETH | ||||
| 38431317 | 2 days ago | 0.000005 ETH |
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {BaseAssetBridge} from "./BaseAssetBridge.sol";
import {IBaseAdapter} from "./adapters/interfaces/IBaseAdapter.sol";
import {IController} from "./interfaces/IController.sol";
import {IFeeCollector} from "./interfaces/IFeeCollector.sol";
import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
/**
* @title AssetController
* @notice This contract is responsible for managing the minting and burning of a specified token across different chains, using a single or multiple bridge adapters.
*/
contract AssetController is Context, BaseAssetBridge, ReentrancyGuard, IController {
using SafeERC20 for IERC20;
/// @notice Event emitted when the token unwrapping setting is changed.
event AllowTokenUnwrappingSet(bool allowUnwrapping);
/// @notice Event emitted when an asset mint message is sent to another chain.
/// @param transferId The unique identifier of the transfer.
/// @param destChainId The destination chain ID.
/// @param threshold The number of bridges required to relay the asset.
/// @param sender The address of the sender.
/// @param recipient The address of the recipient.
/// @param amount The amount of the asset.
event TransferCreated(
bytes32 indexed transferId,
uint256 indexed destChainId,
uint256 threshold,
address indexed sender,
address recipient,
uint256 amount,
bool unwrap
);
/// @notice Event emitted when a transfer can now be executed.
/// @param transferId The unique identifier of the transfer.
event TransferExecutable(bytes32 indexed transferId);
/// @notice Event emitted when an asset is minted on the current chain.
/// @param transferId The unique identifier of the transfer.
event TransferExecuted(bytes32 indexed transferId);
/// @notice Event emitted when transfers to a specific chain are paused or unpaused.
event TransfersPausedToChain(uint256 indexed chainId, bool paused);
/// @notice Event emitted when a transfer is resent.
/// @param transferId The unique identifier of the transfer.
event TransferResent(bytes32 indexed transferId);
/// @notice Event emitted when an asset mint message is sent to another chain via a bridgeAdapter.
/// @param transferId The unique identifier of the transfer.
/// @param bridgeAdapter The address of the bridge adapter.
event TransferRelayed(bytes32 indexed transferId, address bridgeAdapter);
/// @notice Event emitted when an asset is received from another chain.
/// @param transferId The unique identifier of the transfer.
/// @param originChainId The chain id of the origin chain.
/// @param bridgeAdapter The address of the bridge adapter that sent the message.
event TransferReceived(bytes32 indexed transferId, uint256 originChainId, address bridgeAdapter);
/// @notice Event emitted when the minimum number of bridges required to relay an asset for multi-bridge transfers is set.
/// @param minBridges The minimum number of bridges required.
event MinBridgesSet(uint256 minBridges);
/// @notice Event emitted when bridge adapters that can be used for multi-bridge transfers, bypassing the limits have been set
/// @param adapter The address of the bridge adapter.
/// @param enabled The status of the adapter.
event MultiBridgeAdapterSet(address indexed adapter, bool enabled);
/// @notice Event emitted when the controller address for a chain is set.
/// @param controller The address of the controller.
/// @param chainId The chain ID.
event ControllerForChainSet(address indexed controller, uint256 chainId);
/// @notice Error thrown when an asset controller is not deployed/supported on the other chain
error Controller_Chain_Not_Supported();
/// @notice Error thrown when a multibridge adapter specified is not whitelisted
error Controller_AdapterNotSupported();
/// @notice Error thrown when a transfer is not executable
error Controller_TransferNotExecutable();
/// @notice Error thrown when the transferId is not recognized
error Controller_UnknownTransfer();
/// @notice Error thrown when multi-bridge transfers are disabled
error Controller_MultiBridgeTransfersDisabled();
/// @notice Error thrown when the threshold is not met for execution
error Controller_ThresholdNotMet();
/// @notice Error thrown when the msg.value and the sum of fees[] don't match
error Controller_FeesSumMismatch();
/// @notice Error thrown when the adapter is a duplicate in the adapters array
error Controller_DuplicateAdapter();
/// @notice Error thrown when the ether transfer fails
error Controller_EtherTransferFailed();
/// @notice Error thrown when the amount passed is zero
error Controller_ZeroAmount();
/// @notice Error thrown when an adapter resends a transfer that has already been delivered
error Controller_TransferResentByAadapter();
/// @notice Error thrown when transfers to the destination chain are paused
error Controller_TransfersPausedToDestination();
/// @notice Error thrown when the mint function call on the token fails
error Controller_TokenMintFailed();
/// @notice Error thrown when the burn function call on the token fails
error Controller_TokenBurnFailed();
/// @notice Struct representing a bridged asset.
/// @dev This struct holds the details of a message to be relayed to another chain.
struct Transfer {
address recipient;
uint256 amount;
bool unwrap;
uint256 threshold;
bytes32 transferId;
}
/// @notice Struct representing a received transfer.
/// @dev This struct holds the details of a message received from another chain.
struct ReceivedTransfer {
address recipient;
uint256 amount;
bool unwrap;
uint256 receivedSoFar;
uint256 threshold;
uint256 originChainId;
bool executed;
}
/// @dev The fee collector contract address.
IFeeCollector public immutable feeCollector;
/// @dev The local token address that is being bridged.
address public token;
/// @dev Allow XERC20 incoming token transfers to be unwrapped into the native token using the lockbox.
bool public allowTokenUnwrapping;
/// @notice The function selector for the burn(uint256) function on the token.
bytes4 public constant BURN_SELECTOR_SINGLE = bytes4(keccak256(bytes("burn(uint256)"))); // 0x42966c68
/// @notice The function selector for the mint function on the token.
bytes4 public immutable MINT_SELECTOR;
/// @notice The function selector for the burn function on the token.
bytes4 public immutable BURN_SELECTOR;
/// @dev The minimum number of bridges required to relay an asset for multi-bridge transfers.
uint256 public minBridges;
/// @notice Nonce used in transferId calculation, increments after each calculation.
uint256 public nonce;
/// @dev Mapping of chain IDs to their respective controller addresses. This contract knows all the controllers in supported chains.
mapping(uint256 => address) private _controllerForChain;
/// @dev Mapping of whitelisted bridge adapters that can be used for multi-bridge transfers. Used for both sending and receiving messages.
mapping(address => bool) public multiBridgeAdapters;
/// @dev Indicates whether transfers to a given chain ID are currently paused
mapping(uint256 => bool) public transfersPausedTo;
/// @dev Mapping of transfer id to received messages
mapping(bytes32 => ReceivedTransfer) public receivedTransfers;
/// @dev Mapping of transfers identified by their transfer ID.
mapping(bytes32 => Transfer) public relayedTransfers;
/// @dev Mapping of transfer ID to destination chain ID.
mapping(bytes32 => uint256) public destChainForMessage;
/// @dev Mapping of transfer ID to the bridge adapter that has delivered the transfer.
mapping(bytes32 => mapping(address => bool)) public deliveredBy;
/* ========== CONSTRUCTOR ========== */
/**
* @notice Initializes the contract with the given parameters.
* @notice To configure multibridge limits, use the zero address as a bridge in `_bridges` and set the limits accordingly.
* @param _addresses An array with four elements, containing the token address, the user that gets DEFAULT_ADMIN_ROLE and PAUSE_ROLE, the user getting only PAUSE_ROLE,
* the fee collector contract, the controller address in other chains for the given chain IDs (if deployed with create3).
* @param _duration The duration it takes for the limits to fully replenish.
* @param _minBridges The minimum number of bridges required to relay an asset for multi-bridge transfers. Setting to 0 will disable multi-bridge transfers.
* @param _multiBridgeAdapters The addresses of the initial bridge adapters that can be used for multi-bridge transfers, bypassing the limits.
* @param _chainId The list of chain IDs to set the controller addresses for.
* @param _bridges The list of bridge adapter addresses that have limits set for minting and burning.
* @param _mintingLimits The list of minting limits for the bridge adapters. It must correspond to the mint() function of the token, otherwise tokens cannot be minted
* @param _burningLimits The list of burning limits for the bridge adapters. It must correspond to the burn() function of the token, otherwise tokens cannot be burned
* @param _selectors Bytes4 array of mint and burn function selectors.
*/
constructor(
address[5] memory _addresses, //token, initialOwner, pauser, feeCollector, controllerAddress
uint256 _duration,
uint256 _minBridges,
address[] memory _multiBridgeAdapters,
uint256[] memory _chainId,
address[] memory _bridges,
uint256[] memory _mintingLimits,
uint256[] memory _burningLimits,
bytes4[2] memory _selectors
) BaseAssetBridge(_addresses[1], _addresses[2], _duration, _bridges, _mintingLimits, _burningLimits) {
if ((_addresses[0] == address(0)) || (_addresses[3] == address(0))) revert Controller_Invalid_Params();
token = _addresses[0];
feeCollector = IFeeCollector(_addresses[3]);
minBridges = _minBridges;
emit MinBridgesSet(_minBridges);
if (_multiBridgeAdapters.length > 0) {
for (uint256 i = 0; i < _multiBridgeAdapters.length; i++) {
multiBridgeAdapters[_multiBridgeAdapters[i]] = true;
emit MultiBridgeAdapterSet(_multiBridgeAdapters[i], true);
}
}
if (_addresses[4] != address(0)) {
for (uint256 i = 0; i < _chainId.length; i++) {
_controllerForChain[_chainId[i]] = _addresses[4];
emit ControllerForChainSet(_addresses[4], _chainId[i]);
}
}
allowTokenUnwrapping = false;
emit AllowTokenUnwrappingSet(false);
MINT_SELECTOR = _selectors[0];
BURN_SELECTOR = _selectors[1];
}
/* ========== PUBLIC ========== */
/**
* @notice Sends a message to another chain via a bridgeAdapter to mint the asset.
* @dev msg.value should contain the bridge adapter fee
* @param recipient The address of the recipient. Could be the same as msg.sender.
* @param amount The amount of the asset to mint.
* @param unwrap Applicable only to XERC20 transfers. Used to unwrap the native asset using the lockbox on destination, if enabled on the destination.
* @param destChainId The destination chain ID.
* @param bridgeAdapter The address of the bridge adapter.
* @param bridgeOptions Additional params to be used by the adapter.
*/
function transferTo(
address recipient,
uint256 amount,
bool unwrap,
uint256 destChainId,
address bridgeAdapter,
bytes memory bridgeOptions
) public payable nonReentrant whenNotPaused {
if (amount == 0) revert Controller_ZeroAmount();
if (burningCurrentLimitOf(bridgeAdapter) < amount) revert Controller_NotHighEnoughLimits();
_useBurnerLimits(bridgeAdapter, amount);
_burn(_msgSender(), amount);
if (recipient == address(0)) revert Controller_Invalid_Params();
if (getControllerForChain(destChainId) == address(0)) revert Controller_Chain_Not_Supported();
if (transfersPausedTo[destChainId]) revert Controller_TransfersPausedToDestination();
bytes32 transferId = calculateTransferId(destChainId);
// Increment nonce used to create transfer id
nonce++;
// Store transfer data
destChainForMessage[transferId] = destChainId;
Transfer memory transfer = Transfer(recipient, amount, unwrap, 1, transferId);
relayedTransfers[transferId] = transfer;
IBaseAdapter(bridgeAdapter).relayMessage{value: msg.value}(
destChainId,
getControllerForChain(destChainId),
bridgeOptions,
abi.encode(transfer)
);
emit TransferCreated(transferId, destChainId, 1, _msgSender(), recipient, amount, unwrap);
emit TransferRelayed(transferId, bridgeAdapter);
}
/**
* @notice Resends a single-bridge transfer message to another chain via a bridgeAdapter
* @notice Msg.sender will receive any refunds from excess fees paid by the bridge, if the bridge supports it.
* @dev msg.value should contain the bridge adapter fee
* @param transferId The unique identifier of the transfer.
* @param adapter The address of the bridge adapter.
* @param options Additional params to be used by the adapter.
*/
function resendTransfer(bytes32 transferId, address adapter, bytes memory options) public payable nonReentrant whenNotPaused {
uint256 destChainId = destChainForMessage[transferId];
if (destChainId == 0) revert Controller_UnknownTransfer();
Transfer memory transfer = relayedTransfers[transferId];
if (transfer.threshold == 1) {
uint256 _currentLimit = burningCurrentLimitOf(adapter);
if (_currentLimit < transfer.amount) revert Controller_NotHighEnoughLimits();
// Resend doesn't consume burn limits, since the asset is already burned, but it checks if the bridge adapter is enabled
IBaseAdapter(adapter).relayMessage{value: msg.value}(destChainId, getControllerForChain(destChainId), options, abi.encode(transfer));
emit TransferResent(transferId);
emit TransferRelayed(transferId, adapter);
} else {
revert Controller_Invalid_Params();
}
}
/**
* @notice Sends a message to another chain via multiple bridgeAdapter to mint the asset, bypassing the individual bridge limits.
* @notice This function uses instead higher limits, since execution goes through a minimum number of bridges.
* @notice Msg.sender will receive any refunds from excess fees paid by the bridge, if the bridge supports it.
* @dev Token allowance must be given before calling this function, which should include the multi-bridge fee, if any.
* @param recipient The address of the recipient. Could be the same as msg.sender.
* @param amount The amount of the asset to mint.
* @param unwrap Applicable only to XERC20 transfers. Used to unwrap the native asset using the lockbox on destination, if enabled on the destination.
* @param destChainId The destination chain ID.
* @param adapters The addresses of the bridge adapters.
* @param fees The fees to be paid to the bridge adapters.
* @param options Additional params to be used by the adapter.
*/
function transferTo(
address recipient,
uint256 amount,
bool unwrap,
uint256 destChainId,
address[] memory adapters,
uint256[] memory fees,
bytes[] memory options
) public payable nonReentrant whenNotPaused {
if (amount == 0) revert Controller_ZeroAmount();
// Fee collection for multi-bridge transfers
uint256 fee = feeCollector.quote(amount);
if (fee > 0) {
IERC20(token).safeTransferFrom(_msgSender(), address(this), fee);
IERC20(token).safeApprove(address(feeCollector), fee);
feeCollector.collect(token, fee);
}
_burn(_msgSender(), amount);
uint256 _currentLimit = burningCurrentLimitOf(address(0));
if (_currentLimit < amount) revert Controller_NotHighEnoughLimits();
_useBurnerLimits(address(0), amount);
_checkUniqueness(adapters);
// Revert if threshold is higher than the number of adapters that will execute the message
if (adapters.length < minBridges) revert Controller_Invalid_Params();
if (recipient == address(0)) revert Controller_Invalid_Params();
if (minBridges == 0) revert Controller_MultiBridgeTransfersDisabled();
if (getControllerForChain(destChainId) == address(0)) revert Controller_Chain_Not_Supported();
if (transfersPausedTo[destChainId]) revert Controller_TransfersPausedToDestination();
// Create transfer id
bytes32 transferId = calculateTransferId(destChainId);
// Increment nonce used to create transfer id
nonce++;
Transfer memory transfer = Transfer(recipient, amount, unwrap, minBridges, transferId);
// Store transfer data
destChainForMessage[transferId] = destChainId;
relayedTransfers[transferId] = transfer;
_relayTransfer(transfer, destChainId, adapters, fees, options, msg.value);
emit TransferCreated(transferId, destChainId, minBridges, _msgSender(), recipient, amount, unwrap);
}
/**
* @notice Resends a multi-bridge transfer message to another chain via one or more multibridge whitelested bridge Adapters
* @dev msg.value should contain the total bridge adapter fees
* @param transferId The unique identifier of the transfer.
* @param adapters The addresses of the bridge adapters.
* @param fees The fees to be paid to the bridge adapters.
* @param options Additional params to be used by the adapter.
*/
function resendTransfer(
bytes32 transferId,
address[] memory adapters,
uint256[] memory fees,
bytes[] memory options
) public payable nonReentrant whenNotPaused {
uint256 destChainId = destChainForMessage[transferId];
if (destChainId == 0) revert Controller_UnknownTransfer();
if (minBridges == 0) revert Controller_MultiBridgeTransfersDisabled();
_checkUniqueness(adapters);
Transfer memory transfer = relayedTransfers[transferId];
// Resend doesn't uses the burn limits, since the asset is already burned and limits are global for all whitelisted multibridge adapters
if (transfer.threshold > 1) {
if (adapters.length != fees.length) revert Controller_Invalid_Params();
_relayTransfer(transfer, destChainId, adapters, fees, options, msg.value);
emit TransferResent(transferId);
} else {
revert Controller_Invalid_Params();
}
}
/**
* @notice Registers a received message.
* @dev Can be called by an adapter contract only
* @param receivedMsg The received message data in bytes.
* @param originChain The origin chain ID.
* @param originSender The address of the origin sender. (controller in origin chain)
*/
function receiveMessage(bytes calldata receivedMsg, uint256 originChain, address originSender) public override nonReentrant whenNotPaused {
// OriginSender must be a controller on another chain
if (getControllerForChain(originChain) != originSender) revert Controller_Invalid_Params();
// Decode message
Transfer memory transfer = abi.decode(receivedMsg, (Transfer));
if (transfer.threshold == 1) {
// Instant transfer using the bridge limits
// Check that transfer hasn't been replayed
if (receivedTransfers[transfer.transferId].amount != 0) revert Controller_TransferNotExecutable();
receivedTransfers[transfer.transferId] = ReceivedTransfer({
recipient: transfer.recipient,
amount: transfer.amount,
unwrap: transfer.unwrap,
receivedSoFar: 1,
threshold: 1,
originChainId: originChain,
executed: true
});
// Get limit of bridge
uint256 _currentLimit = mintingCurrentLimitOf(msg.sender);
if (_currentLimit < transfer.amount) revert Controller_NotHighEnoughLimits();
_useMinterLimits(msg.sender, transfer.amount);
if (transfer.unwrap && allowTokenUnwrapping) {
_unwrapAndMint(transfer.recipient, transfer.amount);
} else {
_mint(transfer.recipient, transfer.amount);
}
emit TransferExecuted(transfer.transferId);
} else {
// Msg.sender needs to be a multibridge adapter
if (!multiBridgeAdapters[msg.sender]) revert Controller_AdapterNotSupported();
if (deliveredBy[transfer.transferId][msg.sender] == true) revert Controller_TransferResentByAadapter();
deliveredBy[transfer.transferId][msg.sender] = true;
ReceivedTransfer memory receivedTransfer = receivedTransfers[transfer.transferId];
// Multi-bridge transfer
if (receivedTransfer.receivedSoFar == 0) {
receivedTransfer = ReceivedTransfer({
recipient: transfer.recipient,
amount: transfer.amount,
unwrap: transfer.unwrap,
receivedSoFar: 1,
threshold: transfer.threshold,
originChainId: originChain,
executed: false
});
} else {
receivedTransfer.receivedSoFar++;
}
// Check if the transfer can be executed
if (receivedTransfer.receivedSoFar >= receivedTransfer.threshold) {
emit TransferExecutable(transfer.transferId);
}
receivedTransfers[transfer.transferId] = receivedTransfer;
}
emit TransferReceived(transfer.transferId, originChain, msg.sender);
}
/**
* @notice Executes a received multibridge transfer. Anyone can execute a transfer
* @param transferId The unique identifier of the transfer.
*/
function execute(bytes32 transferId) public nonReentrant whenNotPaused {
ReceivedTransfer storage transfer = receivedTransfers[transferId];
if (transfer.amount == 0) revert Controller_UnknownTransfer();
if (transfer.executed) revert Controller_TransferNotExecutable();
if (transfer.receivedSoFar < transfer.threshold) revert Controller_ThresholdNotMet();
uint256 _currentLimit = mintingCurrentLimitOf(address(0));
if (_currentLimit < transfer.amount) revert Controller_NotHighEnoughLimits();
_useMinterLimits(address(0), transfer.amount);
transfer.executed = true;
if (transfer.unwrap && allowTokenUnwrapping) {
_unwrapAndMint(transfer.recipient, transfer.amount);
} else {
_mint(transfer.recipient, transfer.amount);
}
emit TransferExecuted(transferId);
}
/* ========== VIEW ========== */
/**
* @notice Returns the controller address for a given chain ID.
* @param chainId The chain ID.
* @return The controller address.
*/
function getControllerForChain(uint256 chainId) public view override returns (address) {
return _controllerForChain[chainId];
}
/**
* @notice Calculates the transfer ID based on the provided parameters.
* @param destChainId The destination chain ID.
* @return The calculated transfer ID.
*/
function calculateTransferId(uint256 destChainId) public view returns (bytes32) {
return keccak256(abi.encode(destChainId, block.chainid, nonce));
}
/* ========== ADMIN ========== */
function setTokenUnwrapping(bool _allowUnwrapping) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
allowTokenUnwrapping = _allowUnwrapping;
emit AllowTokenUnwrappingSet(_allowUnwrapping);
}
/**
* @notice Sets the controller addresses for the given chain IDs.
* @dev This also serves -in a way- as the token mappers for the token according to xERC20
* @param chainId The list of chain IDs.
* @param controller The list of controller addresses.
*/
function setControllerForChain(uint256[] memory chainId, address[] memory controller) public onlyRole(DEFAULT_ADMIN_ROLE) {
_setControllerForChain(chainId, controller);
}
/**
* @notice Pauses or unpauses the initiation of new transfers to a specific chain.
* @dev Only the owner can call this function.
* @param _chainId The chain ID to pause or unpause transfers to.
* @param _pause True to pause transfers, false to unpause.
*/
function pauseTransfersToChain(uint256 _chainId, bool _pause) public onlyRole(DEFAULT_ADMIN_ROLE) {
transfersPausedTo[_chainId] = _pause;
emit TransfersPausedToChain(_chainId, _pause);
}
/**
* @notice Sets the minimum number of bridges required to relay an asset for multi-bridge transfers.
* @dev Setting to 0 will disable multi-bridge transfers.
* @param _minBridges The minimum number of bridges required.
*/
function setMinBridges(uint256 _minBridges) public onlyRole(DEFAULT_ADMIN_ROLE) {
minBridges = _minBridges;
emit MinBridgesSet(_minBridges);
}
/**
* @notice Adds a bridge adapter to the whitelist for multibridge transfers.
* @dev adapter and enabledmust have the same length.
* @param adapter An array of adapter addresses of the bridge adapters.
* @param enabled An array of the status of the adapters. True to enable, false to disable.
*/
function setMultiBridgeAdapters(address[] memory adapter, bool[] memory enabled) public onlyRole(DEFAULT_ADMIN_ROLE) {
if (adapter.length != enabled.length) revert Controller_Invalid_Params();
for (uint256 i = 0; i < adapter.length; i++) {
multiBridgeAdapters[adapter[i]] = enabled[i];
emit MultiBridgeAdapterSet(adapter[i], enabled[i]);
}
}
/**
*@notice Withdraws the contract balance to the recipient address.
* @dev Only the owner can call this function.
* @param recipient The address to which the contract balance will be transferred.
*/
function withdraw(address payable recipient) public onlyRole(DEFAULT_ADMIN_ROLE) {
if (recipient == address(0)) revert Controller_Invalid_Params();
(bool success, ) = recipient.call{value: address(this).balance}("");
if (!success) revert Controller_EtherTransferFailed();
}
/* ========== INTERNAL ========== */
/**
* @notice Mints the asset to the recipient address, using the MINT_SELECTOR.
* @param recipient The address of the recipient.
* @param amount The amount of the asset to mint.
*/
function _mint(address recipient, uint256 amount) internal virtual {
(bool success, ) = token.call(abi.encodeWithSelector(MINT_SELECTOR, recipient, amount));
if (!success) revert Controller_TokenMintFailed();
}
/**
* @notice Burns the asset from the account address, using the burnSelector.
* @param account The address of the account to burn from.
* @param amount The amount of the asset to burn.
*/
function _burn(address account, uint256 amount) internal virtual {
uint256 balance = IERC20(token).balanceOf(account);
bool success;
if (BURN_SELECTOR == BURN_SELECTOR_SINGLE) {
// burn(uint256) implementations expect msg.sender to hold the tokens
IERC20(token).safeTransferFrom(account, address(this), amount);
(success, ) = token.call(abi.encodeWithSelector(BURN_SELECTOR, amount));
} else {
(success, ) = token.call(abi.encodeWithSelector(BURN_SELECTOR, account, amount));
}
uint256 newBalance = IERC20(token).balanceOf(account);
if (!success || (newBalance != balance - amount)) revert Controller_TokenBurnFailed();
}
/**
* @notice Relays a message to another chain.
* @notice Msg.sender will receive any refunds from excess fees paid by the bridge, if the bridge supports it.
* @param transfer The Transfer struct with the transfer data.
* @param destChainId The destination chain ID.
* @param adapters The list of adapter addresses.
* @param fees The list of fees for each adapter.
* @param totalFees The msg.value passed to the function that should cover the sum of all the fees. Will revert if sum of fees is not equal to totalFees.
*/
function _relayTransfer(
Transfer memory transfer,
uint256 destChainId,
address[] memory adapters,
uint256[] memory fees,
bytes[] memory options,
uint256 totalFees
) internal {
if ((adapters.length != fees.length) || (adapters.length != options.length)) revert Controller_Invalid_Params();
uint256 fee;
for (uint256 i = 0; i < adapters.length; i++) {
// Check that provided bridges are whitelisted
if (multiBridgeAdapters[adapters[i]] == false) revert Controller_AdapterNotSupported();
IBaseAdapter(adapters[i]).relayMessage{value: fees[i]}(destChainId, getControllerForChain(destChainId), options[i], abi.encode(transfer));
emit TransferRelayed(transfer.transferId, adapters[i]);
fee += fees[i];
}
if (fee != totalFees) revert Controller_FeesSumMismatch();
}
/**
* @notice Sets the controller addresses for the given chain IDs.
* @param chainId The list of chain IDs.
* @param controller The list of controller addresses.
*/
function _setControllerForChain(uint256[] memory chainId, address[] memory controller) internal {
if (chainId.length != controller.length) revert Controller_Invalid_Params();
for (uint256 i = 0; i < chainId.length; i++) {
_controllerForChain[chainId[i]] = controller[i];
emit ControllerForChainSet(controller[i], chainId[i]);
}
}
/**
* @notice If there is a XERC20Lockbox set in the token, unwrap the asset and send it to the recipient. If not, mint the tokens directly.
* @dev Checks that all external calls will succeed, otherwise it returns the tokens to the user.
* @param recipient The address of the recipient.
* @param amount The amount of the asset to unwrap and mint.
*/
function _unwrapAndMint(address recipient, uint256 amount) internal virtual {
// Try to get the lockbox address from the token
(bool success, bytes memory data) = token.call(abi.encodeWithSignature("lockbox()"));
// Check if lockbox call was successful and returned data
if (success && data.length != 0) {
address lockbox = abi.decode(data, (address));
// Only attempt unwrapping if lockbox exists
if (lockbox != address(0)) {
// Store initial balance to calculate exact amount after minting
uint256 balanceBefore = IERC20(token).balanceOf(address(this));
// Mint tokens to this contract
_mint(address(this), amount);
// Calculate exact amount received (accounts for potential taxes/fees)
uint256 amountToUnwrap = IERC20(token).balanceOf(address(this)) - balanceBefore;
// Get the underlying token address from lockbox
(bool addrRetrSuccess, bytes memory underlying) = lockbox.call(abi.encodeWithSignature("ERC20()"));
// Approve tokens for unwrapping
(success, ) = token.call(abi.encodeWithSignature("approve(address,uint256)", lockbox, amountToUnwrap));
// If approval failed or underlying token retrieval failed or allowance is insufficient
if (!success || !addrRetrSuccess || IERC20(token).allowance(address(this), lockbox) < amountToUnwrap) {
// Transfer tokens directly to recipient without unwrapping
IERC20(token).safeTransfer(recipient, amountToUnwrap);
return;
}
// Decode underlying token address
address underlyingToken = abi.decode(underlying, (address));
// If underlying token is address(0), can't unwrap
if (underlyingToken == address(0)) {
IERC20(token).safeTransfer(recipient, amountToUnwrap);
return;
}
// Try to withdraw/unwrap tokens
(success, ) = lockbox.call(abi.encodeWithSignature("withdraw(uint256)", amountToUnwrap));
// If withdrawal failed, send the wrapped tokens directly
if (!success) {
IERC20(token).safeTransfer(recipient, amountToUnwrap);
return;
}
// Transfer unwrapped/underlying tokens to recipient
IERC20(underlyingToken).safeTransfer(recipient, amountToUnwrap);
return;
}
}
// If lockbox doesn't exist or can't be used, mint tokens directly to recipient
_mint(recipient, amount);
}
/// @dev Execution will revert if there is a duplicate adapter in the array
function _checkUniqueness(address[] memory adapters) internal pure {
uint256 length = adapters.length;
for (uint256 i = 0; i < length - 1; i++) {
for (uint256 j = i + 1; j < length; j++) {
// Verify that the adapter is not a duplicate
if (adapters[i] == adapters[j]) revert Controller_DuplicateAdapter();
}
}
}
///@dev Fallback function to receive ether from bridge refunds
receive() external payable {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// 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.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.19 <=0.8.20;
interface IBaseAdapter {
/// @notice Struct used by the adapter to relay messages
struct BridgedMessage {
bytes message;
address originController;
address destController;
}
/// @param destChainId The destination chain ID.
/// @param destination The destination address.
/// @param options Additional options to be used by the adapter.
/// @param message The message data to be relayed.
/// @return transferId The transfer ID of the relayed message.
function relayMessage(
uint256 destChainId,
address destination,
bytes memory options,
bytes calldata message
) external payable returns (bytes32 transferId);
/// @param chainId The chain ID to check.
/// @return bool True if the chain ID is supported, false otherwise.
function isChainIdSupported(uint256 chainId) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
/**
* @title BaseAssetBridge
*/
abstract contract BaseAssetBridge is AccessControl, Pausable {
/**
* @notice Error thrown when invalid parameters are provided.
*/
error Controller_Invalid_Params();
/**
* @notice Error thrown when new limits are too high.
*/
error Controller_LimitsTooHigh();
/**
* @notice Emits when a limit is set
*
* @param _mintingLimit The updated minting limit we are setting to the bridge
* @param _burningLimit The updated burning limit we are setting to the bridge
* @param _bridge The address of the bridge we are setting the limit too
*/
event BridgeLimitsSet(uint256 _mintingLimit, uint256 _burningLimit, address indexed _bridge);
/**
* @notice Reverts when a user with too low of a limit tries to call mint/burn
*/
error Controller_NotHighEnoughLimits();
/**
* @notice Contains the full minting and burning data for a particular bridge
*
* @param minterParams The minting parameters for the bridge
* @param burnerParams The burning parameters for the bridge
*/
struct Bridge {
BridgeParameters minterParams;
BridgeParameters burnerParams;
}
/**
* @notice Contains the mint or burn parameters for a bridge
*
* @param timestamp The timestamp of the last mint/burn
* @param ratePerSecond The rate per second of the bridge
* @param maxLimit The max limit of the bridge
* @param currentLimit The current limit of the bridge
*/
struct BridgeParameters {
uint256 timestamp;
uint256 ratePerSecond;
uint256 maxLimit;
uint256 currentLimit;
}
/**
* @notice The role that allows an address to pause the contract
*/
bytes32 public constant PAUSE_ROLE = keccak256("PAUSE_ROLE");
/**
* @notice The duration it takes for the limits to fully replenish
*/
uint256 public duration;
/**
* @notice Maps bridge address to bridge configurations
*/
mapping(address => Bridge) public bridges;
/**
* @notice The constructor for the BaseAssetBridge
*
* @param _owner The user getting the DEFAULT_ADMIN_ROLE and PAUSE_ROLE.
* @param _pauser The user getting the PAUSE_ROLE.
* @param _duration The duration it takes for the limits to fully replenish.
* @param _bridges The list of bridge adapter addresses that have limits set for minting and burning.
* @param _mintingLimits The list of minting limits for the bridge adapters.
* @param _burningLimits The list of burning limits for the bridge adapters.
*/
constructor(
address _owner,
address _pauser,
uint256 _duration,
address[] memory _bridges,
uint256[] memory _mintingLimits,
uint256[] memory _burningLimits
) {
_setupRole(DEFAULT_ADMIN_ROLE, _owner);
_setupRole(PAUSE_ROLE, _owner);
_grantRole(PAUSE_ROLE, _pauser);
if (_duration == 0) revert Controller_Invalid_Params();
duration = _duration;
if ((_bridges.length != _mintingLimits.length) || (_bridges.length != _burningLimits.length)) revert Controller_Invalid_Params();
if (_bridges.length > 0) {
for (uint256 i = 0; i < _bridges.length; i++) {
_setLimits(_bridges[i], _mintingLimits[i], _burningLimits[i]);
}
}
}
/**
* @notice Updates the limits of any bridge
* @dev Can only be called by the owner
* @param _mintingLimit The updated minting limit we are setting to the bridge
* @param _burningLimit The updated burning limit we are setting to the bridge
* @param _bridge The address of the bridge we are setting the limits too
*/
function setLimits(address _bridge, uint256 _mintingLimit, uint256 _burningLimit) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setLimits(_bridge, _mintingLimit, _burningLimit);
}
/**
* @notice Returns the max limit of a bridge
*
* @param _bridge the bridge we are viewing the limits of
* @return _limit The limit the bridge has
*/
function mintingMaxLimitOf(address _bridge) public view returns (uint256 _limit) {
_limit = bridges[_bridge].minterParams.maxLimit;
}
/**
* @notice Returns the max limit of a bridge
*
* @param _bridge the bridge we are viewing the limits of
* @return _limit The limit the bridge has
*/
function burningMaxLimitOf(address _bridge) public view returns (uint256 _limit) {
_limit = bridges[_bridge].burnerParams.maxLimit;
}
/**
* @notice Returns the current limit of a bridge
*
* @param _bridge the bridge we are viewing the limits of
* @return _limit The limit the bridge has
*/
function mintingCurrentLimitOf(address _bridge) public view returns (uint256 _limit) {
_limit = _getCurrentLimit(
bridges[_bridge].minterParams.currentLimit,
bridges[_bridge].minterParams.maxLimit,
bridges[_bridge].minterParams.timestamp,
bridges[_bridge].minterParams.ratePerSecond
);
}
/**
* @notice Returns the current limit of a bridge
*
* @param _bridge the bridge we are viewing the limits of
* @return _limit The limit the bridge has
*/
function burningCurrentLimitOf(address _bridge) public view returns (uint256 _limit) {
_limit = _getCurrentLimit(
bridges[_bridge].burnerParams.currentLimit,
bridges[_bridge].burnerParams.maxLimit,
bridges[_bridge].burnerParams.timestamp,
bridges[_bridge].burnerParams.ratePerSecond
);
}
/**
* @notice Pauses the contract
* @dev Only the owner can call this function.
*/
function pause() external onlyRole(PAUSE_ROLE) {
_pause();
}
/**
* @notice Unpauses the contract
* @dev Only the owner can call this function.
*/
function unpause() external onlyRole(PAUSE_ROLE) {
_unpause();
}
/**
* @notice Updates the limits of any bridge
* @param _mintingLimit The updated minting limit we are setting to the bridge
* @param _burningLimit The updated burning limit we are setting to the bridge
* @param _bridge The address of the bridge we are setting the limits too
*/
function _setLimits(address _bridge, uint256 _mintingLimit, uint256 _burningLimit) internal {
// Ensure new limits do not cause overflows
if (_mintingLimit > (type(uint256).max / 2) || _burningLimit > (type(uint256).max / 2)) {
revert Controller_LimitsTooHigh();
}
_changeMinterLimit(_bridge, _mintingLimit);
_changeBurnerLimit(_bridge, _burningLimit);
emit BridgeLimitsSet(_mintingLimit, _burningLimit, _bridge);
}
/**
* @notice Uses the limit of any bridge
* @param _bridge The address of the bridge who is being changed
* @param _change The change in the limit
*/
function _useMinterLimits(address _bridge, uint256 _change) internal {
uint256 _currentLimit = mintingCurrentLimitOf(_bridge);
bridges[_bridge].minterParams.timestamp = block.timestamp;
bridges[_bridge].minterParams.currentLimit = _currentLimit - _change;
}
/**
* @notice Uses the limit of any bridge
* @param _bridge The address of the bridge who is being changed
* @param _change The change in the limit
*/
function _useBurnerLimits(address _bridge, uint256 _change) internal {
uint256 _currentLimit = burningCurrentLimitOf(_bridge);
bridges[_bridge].burnerParams.timestamp = block.timestamp;
bridges[_bridge].burnerParams.currentLimit = _currentLimit - _change;
}
/**
* @notice Updates the limit of any bridge
* @dev Can only be called by the owner
* @param _bridge The address of the bridge we are setting the limit too
* @param _limit The updated limit we are setting to the bridge
*/
function _changeMinterLimit(address _bridge, uint256 _limit) internal {
uint256 _oldLimit = bridges[_bridge].minterParams.maxLimit;
uint256 _currentLimit = mintingCurrentLimitOf(_bridge);
bridges[_bridge].minterParams.maxLimit = _limit;
bridges[_bridge].minterParams.currentLimit = _calculateNewCurrentLimit(_limit, _oldLimit, _currentLimit);
bridges[_bridge].minterParams.ratePerSecond = _limit / duration;
bridges[_bridge].minterParams.timestamp = block.timestamp;
}
function _changeBurnerLimit(address _bridge, uint256 _limit) internal {
uint256 _oldLimit = bridges[_bridge].burnerParams.maxLimit;
uint256 _currentLimit = burningCurrentLimitOf(_bridge);
bridges[_bridge].burnerParams.maxLimit = _limit;
bridges[_bridge].burnerParams.currentLimit = _calculateNewCurrentLimit(_limit, _oldLimit, _currentLimit);
bridges[_bridge].burnerParams.ratePerSecond = _limit / duration;
bridges[_bridge].burnerParams.timestamp = block.timestamp;
}
/**
* @notice Updates the current limit
*
* @param _limit The new limit
* @param _oldLimit The old limit
* @param _currentLimit The current limit
* @return _newCurrentLimit The new current limit
*/
function _calculateNewCurrentLimit(uint256 _limit, uint256 _oldLimit, uint256 _currentLimit) internal pure returns (uint256 _newCurrentLimit) {
uint256 _difference;
if (_oldLimit > _limit) {
_difference = _oldLimit - _limit;
_newCurrentLimit = _currentLimit > _difference ? _currentLimit - _difference : 0;
} else {
_difference = _limit - _oldLimit;
_newCurrentLimit = _currentLimit + _difference;
}
}
/**
* @notice Gets the current limit
*
* @param _currentLimit The current limit
* @param _maxLimit The max limit
* @param _timestamp The timestamp of the last update
* @param _ratePerSecond The rate per second
* @return _limit The current limit
*/
function _getCurrentLimit(
uint256 _currentLimit,
uint256 _maxLimit,
uint256 _timestamp,
uint256 _ratePerSecond
) internal view returns (uint256 _limit) {
_limit = _currentLimit;
if (_limit == _maxLimit) {
return _limit;
} else if (_timestamp + duration <= block.timestamp) {
_limit = _maxLimit;
} else if (_timestamp + duration > block.timestamp) {
uint256 _timePassed = block.timestamp - _timestamp;
uint256 _calculatedLimit = _limit + (_timePassed * _ratePerSecond);
_limit = _calculatedLimit > _maxLimit ? _maxLimit : _calculatedLimit;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.19 <=0.8.20;
interface IController {
/**
* @notice Registers a received message.
* @param message The received message data in bytes.
* @param originChain The origin chain ID.
* @param originSender The address of the origin sender. (controller in origin chain)
*/
function receiveMessage(bytes calldata message, uint256 originChain, address originSender) external;
/**
* @notice Returns the controller address for a given chain ID.
* @param chainId The chain ID.
* @return The controller address.
*/
function getControllerForChain(uint256 chainId) external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
interface IFeeCollector {
function collect(address token, uint256 amount) external;
function quote(uint256 amount) external view returns (uint256 fee);
}{
"evmVersion": "london",
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address[5]","name":"_addresses","type":"address[5]"},{"internalType":"uint256","name":"_duration","type":"uint256"},{"internalType":"uint256","name":"_minBridges","type":"uint256"},{"internalType":"address[]","name":"_multiBridgeAdapters","type":"address[]"},{"internalType":"uint256[]","name":"_chainId","type":"uint256[]"},{"internalType":"address[]","name":"_bridges","type":"address[]"},{"internalType":"uint256[]","name":"_mintingLimits","type":"uint256[]"},{"internalType":"uint256[]","name":"_burningLimits","type":"uint256[]"},{"internalType":"bytes4[2]","name":"_selectors","type":"bytes4[2]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Controller_AdapterNotSupported","type":"error"},{"inputs":[],"name":"Controller_Chain_Not_Supported","type":"error"},{"inputs":[],"name":"Controller_DuplicateAdapter","type":"error"},{"inputs":[],"name":"Controller_EtherTransferFailed","type":"error"},{"inputs":[],"name":"Controller_FeesSumMismatch","type":"error"},{"inputs":[],"name":"Controller_Invalid_Params","type":"error"},{"inputs":[],"name":"Controller_LimitsTooHigh","type":"error"},{"inputs":[],"name":"Controller_MultiBridgeTransfersDisabled","type":"error"},{"inputs":[],"name":"Controller_NotHighEnoughLimits","type":"error"},{"inputs":[],"name":"Controller_ThresholdNotMet","type":"error"},{"inputs":[],"name":"Controller_TokenBurnFailed","type":"error"},{"inputs":[],"name":"Controller_TokenMintFailed","type":"error"},{"inputs":[],"name":"Controller_TransferNotExecutable","type":"error"},{"inputs":[],"name":"Controller_TransferResentByAadapter","type":"error"},{"inputs":[],"name":"Controller_TransfersPausedToDestination","type":"error"},{"inputs":[],"name":"Controller_UnknownTransfer","type":"error"},{"inputs":[],"name":"Controller_ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"allowUnwrapping","type":"bool"}],"name":"AllowTokenUnwrappingSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_mintingLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_burningLimit","type":"uint256"},{"indexed":true,"internalType":"address","name":"_bridge","type":"address"}],"name":"BridgeLimitsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"ControllerForChainSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minBridges","type":"uint256"}],"name":"MinBridgesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"adapter","type":"address"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"MultiBridgeAdapterSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transferId","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"destChainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"threshold","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"unwrap","type":"bool"}],"name":"TransferCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transferId","type":"bytes32"}],"name":"TransferExecutable","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transferId","type":"bytes32"}],"name":"TransferExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transferId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"originChainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"bridgeAdapter","type":"address"}],"name":"TransferReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transferId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"bridgeAdapter","type":"address"}],"name":"TransferRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transferId","type":"bytes32"}],"name":"TransferResent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"TransfersPausedToChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"BURN_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BURN_SELECTOR_SINGLE","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINT_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowTokenUnwrapping","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bridges","outputs":[{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"ratePerSecond","type":"uint256"},{"internalType":"uint256","name":"maxLimit","type":"uint256"},{"internalType":"uint256","name":"currentLimit","type":"uint256"}],"internalType":"struct BaseAssetBridge.BridgeParameters","name":"minterParams","type":"tuple"},{"components":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"ratePerSecond","type":"uint256"},{"internalType":"uint256","name":"maxLimit","type":"uint256"},{"internalType":"uint256","name":"currentLimit","type":"uint256"}],"internalType":"struct BaseAssetBridge.BridgeParameters","name":"burnerParams","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bridge","type":"address"}],"name":"burningCurrentLimitOf","outputs":[{"internalType":"uint256","name":"_limit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bridge","type":"address"}],"name":"burningMaxLimitOf","outputs":[{"internalType":"uint256","name":"_limit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"destChainId","type":"uint256"}],"name":"calculateTransferId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"deliveredBy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"destChainForMessage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"duration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transferId","type":"bytes32"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"contract IFeeCollector","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"getControllerForChain","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minBridges","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bridge","type":"address"}],"name":"mintingCurrentLimitOf","outputs":[{"internalType":"uint256","name":"_limit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bridge","type":"address"}],"name":"mintingMaxLimitOf","outputs":[{"internalType":"uint256","name":"_limit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"multiBridgeAdapters","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"},{"internalType":"bool","name":"_pause","type":"bool"}],"name":"pauseTransfersToChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"receivedMsg","type":"bytes"},{"internalType":"uint256","name":"originChain","type":"uint256"},{"internalType":"address","name":"originSender","type":"address"}],"name":"receiveMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"receivedTransfers","outputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"receivedSoFar","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"uint256","name":"originChainId","type":"uint256"},{"internalType":"bool","name":"executed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"relayedTransfers","outputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"bytes32","name":"transferId","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transferId","type":"bytes32"},{"internalType":"address","name":"adapter","type":"address"},{"internalType":"bytes","name":"options","type":"bytes"}],"name":"resendTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transferId","type":"bytes32"},{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"uint256[]","name":"fees","type":"uint256[]"},{"internalType":"bytes[]","name":"options","type":"bytes[]"}],"name":"resendTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"chainId","type":"uint256[]"},{"internalType":"address[]","name":"controller","type":"address[]"}],"name":"setControllerForChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bridge","type":"address"},{"internalType":"uint256","name":"_mintingLimit","type":"uint256"},{"internalType":"uint256","name":"_burningLimit","type":"uint256"}],"name":"setLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minBridges","type":"uint256"}],"name":"setMinBridges","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"adapter","type":"address[]"},{"internalType":"bool[]","name":"enabled","type":"bool[]"}],"name":"setMultiBridgeAdapters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_allowUnwrapping","type":"bool"}],"name":"setTokenUnwrapping","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"destChainId","type":"uint256"},{"internalType":"address[]","name":"adapters","type":"address[]"},{"internalType":"uint256[]","name":"fees","type":"uint256[]"},{"internalType":"bytes[]","name":"options","type":"bytes[]"}],"name":"transferTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"unwrap","type":"bool"},{"internalType":"uint256","name":"destChainId","type":"uint256"},{"internalType":"address","name":"bridgeAdapter","type":"address"},{"internalType":"bytes","name":"bridgeOptions","type":"bytes"}],"name":"transferTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfersPausedTo","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60e06040523480156200001157600080fd5b506040516200517738038062005177833981016040819052620000349162000b15565b602089015160408a01516001805460ff1916905589868686620000596000876200048b565b6200007460008051602062005157833981519152876200048b565b6200008f60008051602062005157833981519152866200049b565b83600003620000b157604051633f4e2f2960e21b815260040160405180910390fd5b600284905581518351141580620000ca57508051835114155b15620000e957604051633f4e2f2960e21b815260040160405180910390fd5b8251156200017c5760005b83518110156200017a576200016584828151811062000117576200011762000c37565b602002602001015184838151811062000134576200013462000c37565b602002602001015184848151811062000151576200015162000c37565b60200260200101516200052360201b60201c565b80620001718162000c63565b915050620000f4565b505b5050600160045550508a516001600160a01b0316159150819050620001ac575060608901516001600160a01b0316155b15620001cb57604051633f4e2f2960e21b815260040160405180910390fd5b8851600580546001600160a01b0319166001600160a01b0392831617905560608a01511660805260068790556040518781527fe125065bd51f3e795dd066e6f64e43cedd27dc38adf0062c7be9eaa209ae11479060200160405180910390a1855115620003135760005b865181101562000311576001600960008984815181106200025a576200025a62000c37565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550868181518110620002ae57620002ae62000c37565b60200260200101516001600160a01b03167fd3577f4d8ca054ac85e150e2a592220c54234d070e9f8ed0199869b7a17b25206001604051620002f4911515815260200190565b60405180910390a280620003088162000c63565b91505062000235565b505b60808901516001600160a01b031615620004205760005b85518110156200041e5789600460200201516008600088848151811062000355576200035562000c37565b6020026020010151815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555089600460058110620003a557620003a562000c37565b60200201516001600160a01b03167f3083b3b95a46df5c4a6cdd1fa242b76f968ed75bf364ec15de70e5b043f62831878381518110620003e957620003e962000c37565b60200260200101516040516200040191815260200190565b60405180910390a280620004158162000c63565b9150506200032a565b505b6005805460ff60a01b19169055604051600081527f2b777c07ea46054410835bc43625d87926c44d9a6b4ec49a7e3248d434cfe5b59060200160405180910390a180516001600160e01b031990811660a0526020909101511660c0525062000ce89650505050505050565b6200049782826200049b565b5050565b620004a78282620005cd565b62000497576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620004df3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b62000532600260001962000c7f565b8211806200054d57506200054a600260001962000c7f565b81115b156200056c576040516301e8cafb60e71b815260040160405180910390fd5b620005788383620005f8565b620005848382620006a3565b60408051838152602081018390526001600160a01b038516917f93f3bbfe8cfb354ec059175107653f49f6eb479a8622a7d83866ea015435c944910160405180910390a2505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff165b92915050565b6001600160a01b03821660009081526003602052604081206002015490620006208462000753565b6001600160a01b038516600090815260036020526040902060020184905590506200064d8383836200078a565b6001600160a01b0385166000908152600360208190526040909120015560025462000679908462000c7f565b6001600160a01b039094166000908152600360205260409020600181019490945550504290915550565b6001600160a01b03821660009081526003602052604081206006015490620006cb84620007ed565b6001600160a01b03851660009081526003602052604090206006018490559050620006f88383836200078a565b6001600160a01b03851660009081526003602052604090206007015560025462000723908462000c7f565b6001600160a01b039094166000908152600360205260409020600581019490945550504260049092019190915550565b6001600160a01b038116600090815260036020819052604082209081015460028201548254600190930154620005f2939062000821565b60008084841115620007c857620007a2858562000ca2565b9050808311620007b4576000620007c0565b620007c0818462000ca2565b9150620007e5565b620007d4848662000ca2565b9050620007e2818462000cb8565b91505b509392505050565b6001600160a01b0381166000908152600360205260408120600781015460068201546004830154600590930154620005f293905b83838114620008a35742600254846200083b919062000cb8565b1162000849575082620008a3565b42600254846200085a919062000cb8565b1115620008a35760006200086f844262000ca2565b905060006200087f848362000cce565b6200088b908462000cb8565b90508581116200089c57806200089e565b855b925050505b949350505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620008ec57620008ec620008ab565b604052919050565b80516001600160a01b03811681146200090c57600080fd5b919050565b600082601f8301126200092357600080fd5b60405160a081016001600160401b0381118282101715620009485762000948620008ab565b6040528060a08401858111156200095e57600080fd5b845b8181101562000983576200097481620008f4565b83526020928301920162000960565b509195945050505050565b60006001600160401b03821115620009aa57620009aa620008ab565b5060051b60200190565b600082601f830112620009c657600080fd5b81516020620009df620009d9836200098e565b620008c1565b82815260059290921b84018101918181019086841115620009ff57600080fd5b8286015b8481101562000a255762000a1781620008f4565b835291830191830162000a03565b509695505050505050565b600082601f83011262000a4257600080fd5b8151602062000a55620009d9836200098e565b82815260059290921b8401810191818101908684111562000a7557600080fd5b8286015b8481101562000a25578051835291830191830162000a79565b600082601f83011262000aa457600080fd5b604080519081016001600160401b038111828210171562000ac95762000ac9620008ab565b806040525080604084018581111562000ae157600080fd5b845b81811015620009835780516001600160e01b03198116811462000b065760008081fd5b83526020928301920162000ae3565b60008060008060008060008060006101c08a8c03121562000b3557600080fd5b62000b418b8b62000911565b60a08b015160c08c015160e08d0151929b5090995097506001600160401b038082111562000b6e57600080fd5b62000b7c8d838e01620009b4565b97506101008c015191508082111562000b9457600080fd5b62000ba28d838e0162000a30565b96506101208c015191508082111562000bba57600080fd5b62000bc88d838e01620009b4565b95506101408c015191508082111562000be057600080fd5b62000bee8d838e0162000a30565b94506101608c015191508082111562000c0657600080fd5b5062000c158c828d0162000a30565b92505062000c288b6101808c0162000a92565b90509295985092959850929598565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820162000c785762000c7862000c4d565b5060010190565b60008262000c9d57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115620005f257620005f262000c4d565b80820180821115620005f257620005f262000c4d565b8082028115828204841417620005f257620005f262000c4d565b60805160a05160c05161440e62000d496000396000818161071c01528181612459015281816124d001526125a20152600081816105b901526130260152600081816108e301528181610dde01528181610e830152610ed1015261440e6000f3fe6080604052600436106102805760003560e01c80637385e7fb1161014f578063c1eb7137116100c1578063d3a8b6311161007a578063d3a8b63114610a08578063d547741f14610a1b578063d6991b5b14610a3b578063e751f27114610a5b578063eab6995814610a7b578063fc0c546a14610a9157600080fd5b8063c1eb713714610898578063c415b95c146108d1578063cdf0366f1461091d578063ced67f0c1461093d578063d236ad68146109d5578063d30a41c8146109f557600080fd5b806391d148541161011357806391d148541461075f578063968638861461077f578063998955d31461082d578063a08d56541461084d578063a217fddf1461086d578063affed0e01461088257600080fd5b80637385e7fb1461066c5780637e0a8c6a1461069c5780638456cb59146106f557806387a131bb1461070a57806389a3b4fb1461073e57600080fd5b806336568abe116101f357806351cff8d9116101ac57806351cff8d914610587578063544fe464146105a75780635c975abb146105f4578063651fd2681461060c5780637256d8721461062c578063734afa2b1461064c57600080fd5b806336568abe146104d8578063365fc213146104f8578063389ed2671461051857806339c82de61461054c5780633f4ba83a1461055f5780634995c3e71461057457600080fd5b806315af3b671161024557806315af3b671461036d5780631f9bb777146103a8578063215e73e114610438578063248a9ca31461046857806327a65d3f146104985780632f2ff15d146104b857600080fd5b80625856cb1461028c57806301ffc9a7146102cc5780630c05f82c146102fc5780630fb5a6b41461033557806312ca7dbb1461034b57600080fd5b3661028757005b600080fd5b34801561029857600080fd5b506102b96102a7366004613956565b600d6020526000908152604090205481565b6040519081526020015b60405180910390f35b3480156102d857600080fd5b506102ec6102e736600461396f565b610ab1565b60405190151581526020016102c3565b34801561030857600080fd5b506102b96103173660046139ae565b6001600160a01b031660009081526003602052604090206002015490565b34801561034157600080fd5b506102b960025481565b34801561035757600080fd5b5061036b6103663660046139d9565b610ae8565b005b34801561037957600080fd5b506102ec610388366004613a09565b600e60209081526000928352604080842090915290825290205460ff1681565b3480156103b457600080fd5b506104006103c3366004613956565b600c60205260009081526040902080546001820154600283015460038401546004909401546001600160a01b0390931693919260ff909116919085565b604080516001600160a01b0390961686526020860194909452911515928401929092526060830191909152608082015260a0016102c3565b34801561044457600080fd5b506102ec6104533660046139ae565b60096020526000908152604090205460ff1681565b34801561047457600080fd5b506102b9610483366004613956565b60009081526020819052604090206001015490565b3480156104a457600080fd5b5061036b6104b3366004613b0b565b610b4c565b3480156104c457600080fd5b5061036b6104d3366004613a09565b610c83565b3480156104e457600080fd5b5061036b6104f3366004613a09565b610cad565b34801561050457600080fd5b5061036b610513366004613bce565b610d30565b34801561052457600080fd5b506102b97f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d81565b61036b61055a366004613d34565b610d94565b34801561056b57600080fd5b5061036b6111bf565b61036b610582366004613df4565b6111f4565b34801561059357600080fd5b5061036b6105a23660046139ae565b6113fa565b3480156105b357600080fd5b506105db7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160e01b031990911681526020016102c3565b34801561060057600080fd5b5060015460ff166102ec565b34801561061857600080fd5b506102b96106273660046139ae565b6114a0565b34801561063857600080fd5b506102b9610647366004613956565b6114d5565b34801561065857600080fd5b5061036b610667366004613e4c565b61151c565b34801561067857600080fd5b506102ec610687366004613956565b600a6020526000908152604090205460ff1681565b3480156106a857600080fd5b5060408051808201909152600d81526c6275726e2875696e743235362960981b6020909101526105db7f42966c689b5afe9b9b3f8a7103b2a19980d59629bfd6a20a60972312ed41d83681565b34801561070157600080fd5b5061036b6119ca565b34801561071657600080fd5b506105db7f000000000000000000000000000000000000000000000000000000000000000081565b34801561074a57600080fd5b506005546102ec90600160a01b900460ff1681565b34801561076b57600080fd5b506102ec61077a366004613a09565b6119fc565b34801561078b57600080fd5b506107e661079a366004613956565b600b6020526000908152604090208054600182015460028301546003840154600485015460058601546006909601546001600160a01b0390951695939460ff9384169492939192911687565b604080516001600160a01b0390981688526020880196909652931515948601949094526060850191909152608084015260a0830191909152151560c082015260e0016102c3565b34801561083957600080fd5b506102b96108483660046139ae565b611a25565b34801561085957600080fd5b5061036b610868366004613ed6565b611a5c565b34801561087957600080fd5b506102b9600081565b34801561088e57600080fd5b506102b960075481565b3480156108a457600080fd5b506102b96108b33660046139ae565b6001600160a01b031660009081526003602052604090206006015490565b3480156108dd57600080fd5b506109057f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102c3565b34801561092957600080fd5b5061036b610938366004613f0b565b611a72565b34801561094957600080fd5b506109c76109583660046139ae565b60036020818152600092835260409283902083516080808201865282548252600183015482850152600283015482870152938201546060808301919091528551948501865260048301548552600583015493850193909352600682015494840194909452600701549082015282565b6040516102c3929190613f6e565b3480156109e157600080fd5b5061036b6109f0366004613956565b611a87565b61036b610a03366004613fba565b611ac7565b61036b610a16366004614040565b611db9565b348015610a2757600080fd5b5061036b610a36366004613a09565b611eee565b348015610a4757600080fd5b50610905610a56366004613956565b611f13565b348015610a6757600080fd5b5061036b610a76366004613956565b611f2e565b348015610a8757600080fd5b506102b960065481565b348015610a9d57600080fd5b50600554610905906001600160a01b031681565b60006001600160e01b03198216637965db0b60e01b1480610ae257506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000610af3816120a3565b6000838152600a6020908152604091829020805460ff1916851515908117909155915191825284917f8670d56066b58d6b5eff6e9ff63fb7bc28c6d4ec9676c45cf2360314e9e9c24a91015b60405180910390a2505050565b6000610b57816120a3565b8151835114610b7957604051633f4e2f2960e21b815260040160405180910390fd5b60005b8351811015610c7d57828181518110610b9757610b976140d1565b602002602001015160096000868481518110610bb557610bb56140d1565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550838181518110610c0657610c066140d1565b60200260200101516001600160a01b03167fd3577f4d8ca054ac85e150e2a592220c54234d070e9f8ed0199869b7a17b2520848381518110610c4a57610c4a6140d1565b6020026020010151604051610c63911515815260200190565b60405180910390a280610c75816140fd565b915050610b7c565b50505050565b600082815260208190526040902060010154610c9e816120a3565b610ca883836120ad565b505050565b6001600160a01b0381163314610d225760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610d2c8282612131565b5050565b6000610d3b816120a3565b60058054831515600160a01b0260ff60a01b199091161790556040517f2b777c07ea46054410835bc43625d87926c44d9a6b4ec49a7e3248d434cfe5b590610d8890841515815260200190565b60405180910390a15050565b610d9c612196565b610da46121ef565b85600003610dc557604051636c13c71b60e01b815260040160405180910390fd5b604051633b46f5db60e21b8152600481018790526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ed1bd76c90602401602060405180830381865afa158015610e2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e519190614116565b90508015610f3057610e71336005546001600160a01b0316903084612237565b600554610ea8906001600160a01b03167f0000000000000000000000000000000000000000000000000000000000000000836122a2565b600554604051631ae0d5eb60e21b81526001600160a01b039182166004820152602481018390527f000000000000000000000000000000000000000000000000000000000000000090911690636b8357ac90604401600060405180830381600087803b158015610f1757600080fd5b505af1158015610f2b573d6000803e3d6000fd5b505050505b610f3a33886123b7565b6000610f466000611a25565b905087811015610f6957604051633ebc3cb560e11b815260040160405180910390fd5b610f746000896126d2565b610f7d8561272c565b60065485511015610fa157604051633f4e2f2960e21b815260040160405180910390fd5b6001600160a01b038916610fc857604051633f4e2f2960e21b815260040160405180910390fd5b600654600003610feb5760405163d123a59d60e01b815260040160405180910390fd5b6000610ff687611f13565b6001600160a01b03160361101d57604051634ea9399d60e01b815260040160405180910390fd5b6000868152600a602052604090205460ff161561104d5760405163e5d48ceb60e01b815260040160405180910390fd5b6000611058876114d5565b60078054919250600061106a836140fd565b919050555060006040518060a001604052808c6001600160a01b031681526020018b81526020018a15158152602001600654815260200183815250905087600d60008481526020019081526020016000208190555080600c600084815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506020820151816001015560408201518160020160006101000a81548160ff021916908315150217905550606082015181600301556080820151816004015590505061114f8189898989346127e4565b600654604080519182526001600160a01b038d16602083015281018b905289151560608201523390899084907f7214d2a3fc41a2bc94a7a69749a3d127afd8d8e79e0573dbe7892d84ee6fdd749060800160405180910390a4505050506111b66001600455565b50505050505050565b7f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d6111e9816120a3565b6111f1612a29565b50565b6111fc612196565b6112046121ef565b6000838152600d6020526040812054908190036112345760405163789d685360e01b815260040160405180910390fd5b6000848152600c6020908152604091829020825160a08101845281546001600160a01b0316815260018083015493820193909352600282015460ff16151593810193909352600381015460608401819052600490910154608084015290036113d55760006112a185611a25565b905081602001518110156112c857604051633ebc3cb560e11b815260040160405180910390fd5b846001600160a01b031663a4cbec7334856112e287611f13565b88876040516020016112f4919061412f565b6040516020818303038152906040526040518663ffffffff1660e01b815260040161132294939291906141bf565b60206040518083038185885af1158015611340573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906113659190614116565b5060405186907fdc2df65ad98a3640553c4a6fa9e8b28b7cac67002cff20bfa132ad69b51b9e6d90600090a26040516001600160a01b038616815286907f5a94fe36b9c96bbd30dafe9eb364e4d1ac0751c6f8c114bd0977952694149c079060200160405180910390a2506113ee565b604051633f4e2f2960e21b815260040160405180910390fd5b5050610ca86001600455565b6000611405816120a3565b6001600160a01b03821661142c57604051633f4e2f2960e21b815260040160405180910390fd5b6000826001600160a01b03164760405160006040518083038185875af1925050503d8060008114611479576040519150601f19603f3d011682016040523d82523d6000602084013e61147e565b606091505b5050905080610ca857604051631bc19cc560e31b815260040160405180910390fd5b6001600160a01b038116600090815260036020819052604082209081015460028201548254600190930154610ae29390612a7b565b600081466007546040516020016114ff939291909283526020830191909152604082015260600190565b604051602081830303815290604052805190602001209050919050565b611524612196565b61152c6121ef565b806001600160a01b031661153f83611f13565b6001600160a01b03161461156657604051633f4e2f2960e21b815260040160405180910390fd5b600061157484860186614206565b905080606001516001036117325760808101516000908152600b6020526040902060010154156115b757604051632da0ab1960e01b815260040160405180910390fd5b6040805160e08101825282516001600160a01b039081168252602080850151818401908152858501511515848601908152600160608601818152608080880183815260a089018d815260c08a01858152928c01516000908152600b9098529987209851895498166001600160a01b0319909816979097178855935191870191909155905160028601805491151560ff1992831617905590516003860155925160048501559351600584015592516006909201805492151592909116919091179055611681336114a0565b905081602001518110156116a857604051633ebc3cb560e11b815260040160405180910390fd5b6116b6338360200151612af5565b816040015180156116d05750600554600160a01b900460ff165b156116ec576116e782600001518360200151612b4c565b6116fe565b6116fe82600001518360200151613002565b60808201516040517fe843a2101c5af088cd2648db06f117411c38047d50a9f499f99cd99adb41490a90600090a250611982565b3360009081526009602052604090205460ff1661176257604051635cfb665160e01b815260040160405180910390fd5b60808101516000908152600e6020908152604080832033845290915290205460ff1615156001036117a65760405163c7d1b4c160e01b815260040160405180910390fd5b608080820180516000908152600e602090815260408083203384528252808320805460ff1916600190811790915593518352600b8252808320815160e08101835281546001600160a01b031681529481015492850192909252600282015460ff908116151591850191909152600382015460608501819052600483015495850195909552600582015460a085015260069091015416151560c0830152909190036118a3576040518060e0016040528083600001516001600160a01b031681526020018360200151815260200183604001511515815260200160018152602001836060015181526020018581526020016000151581525090506118b7565b606081018051906118b3826140fd565b9052505b80608001518160600151106118f55760808201516040517fb23e240f843ae6fd7bc9d43aef3333ff0333d69a51e80b0d869df7546162622590600090a25b6080808301516000908152600b6020908152604091829020845181546001600160a01b039091166001600160a01b03199091161781559084015160018201559083015160028201805491151560ff199283161790556060840151600383015591830151600482015560a0830151600582015560c09092015160069092018054921515929091169190911790555b6080810151604080518581523360208201527fb56eee7198c2db26c3593517941abaa02608050011d356b4f29e8a5c6a269aed910160405180910390a250610c7d6001600455565b7f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d6119f4816120a3565b6111f16130eb565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6001600160a01b0381166000908152600360205260408120600781015460068201546004830154600590930154610ae29390612a7b565b6000611a67816120a3565b610c7d848484613126565b6000611a7d816120a3565b610ca883836131be565b6000611a92816120a3565b60068290556040518281527fe125065bd51f3e795dd066e6f64e43cedd27dc38adf0062c7be9eaa209ae114790602001610d88565b611acf612196565b611ad76121ef565b84600003611af857604051636c13c71b60e01b815260040160405180910390fd5b84611b0283611a25565b1015611b2157604051633ebc3cb560e11b815260040160405180910390fd5b611b2b82866126d2565b611b3533866123b7565b6001600160a01b038616611b5c57604051633f4e2f2960e21b815260040160405180910390fd5b6000611b6784611f13565b6001600160a01b031603611b8e57604051634ea9399d60e01b815260040160405180910390fd5b6000838152600a602052604090205460ff1615611bbe5760405163e5d48ceb60e01b815260040160405180910390fd5b6000611bc9846114d5565b600780549192506000611bdb836140fd565b90915550506000818152600d60209081526040808320879055805160a0810182526001600160a01b038b811682528184018b81528a1515838501908152600160608501818152608086018a81528a8a52600c90985295909720845181546001600160a01b031916908516178155915196820196909655945160028601805460ff191691151591909117905591516003850155915160049093019290925590841663a4cbec733487611c8b81611f13565b8786604051602001611c9d919061412f565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611ccb94939291906141bf565b60206040518083038185885af1158015611ce9573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611d0e9190614116565b5060408051600181526001600160a01b038a166020820152808201899052871515606082015290513391879185917f7214d2a3fc41a2bc94a7a69749a3d127afd8d8e79e0573dbe7892d84ee6fdd74919081900360800190a46040516001600160a01b038516815282907f5a94fe36b9c96bbd30dafe9eb364e4d1ac0751c6f8c114bd0977952694149c079060200160405180910390a25050611db16001600455565b505050505050565b611dc1612196565b611dc96121ef565b6000848152600d602052604081205490819003611df95760405163789d685360e01b815260040160405180910390fd5b600654600003611e1c5760405163d123a59d60e01b815260040160405180910390fd5b611e258461272c565b6000858152600c6020908152604091829020825160a08101845281546001600160a01b0316815260018083015493820193909352600282015460ff16151593810193909352600381015460608401819052600490910154608084015211156113d5578351855114611ea957604051633f4e2f2960e21b815260040160405180910390fd5b611eb78183878787346127e4565b60405186907fdc2df65ad98a3640553c4a6fa9e8b28b7cac67002cff20bfa132ad69b51b9e6d90600090a25050610c7d6001600455565b600082815260208190526040902060010154611f09816120a3565b610ca88383612131565b6000908152600860205260409020546001600160a01b031690565b611f36612196565b611f3e6121ef565b6000818152600b602052604081206001810154909103611f715760405163789d685360e01b815260040160405180910390fd5b600681015460ff1615611f9757604051632da0ab1960e01b815260040160405180910390fd5b806004015481600301541015611fc057604051631b8d5dc160e01b815260040160405180910390fd5b6000611fcc60006114a0565b90508160010154811015611ff357604051633ebc3cb560e11b815260040160405180910390fd5b61200260008360010154612af5565b60068201805460ff19166001179055600282015460ff16801561202e5750600554600160a01b900460ff165b15612052578154600183015461204d916001600160a01b031690612b4c565b61206c565b8154600183015461206c916001600160a01b031690613002565b60405183907fe843a2101c5af088cd2648db06f117411c38047d50a9f499f99cd99adb41490a90600090a250506111f16001600455565b6111f181336132dd565b6120b782826119fc565b610d2c576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556120ed3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b61213b82826119fc565b15610d2c576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6002600454036121e85760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d19565b6002600455565b60015460ff16156122355760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610d19565b565b6040516001600160a01b0380851660248301528316604482015260648101829052610c7d9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613336565b80158061231c5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156122f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231a9190614116565b155b6123875760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610d19565b6040516001600160a01b038316602482015260448101829052610ca890849063095ea7b360e01b9060640161226b565b6005546040516370a0823160e01b81526001600160a01b03848116600483015260009216906370a0823190602401602060405180830381865afa158015612402573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124269190614116565b60408051808201909152600d81526c6275726e2875696e743235362960981b602090910152905060006317ad327360e31b7f00000000000000000000000000000000000000000000000000000000000000006001600160e01b031916016125615760055461249f906001600160a01b0316853086612237565b60055460408051602480820187905282518083039091018152604490910182526020810180516001600160e01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160e01b03191617905290516001600160a01b03909216916125149190614284565b6000604051808303816000865af19150503d8060008114612551576040519150601f19603f3d011682016040523d82523d6000602084013e612556565b606091505b505080915050612626565b600554604080516001600160a01b038781166024830152604480830188905283518084039091018152606490920183526020820180516001600160e01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160e01b031916179052915191909216916125de91614284565b6000604051808303816000865af19150503d806000811461261b576040519150601f19603f3d011682016040523d82523d6000602084013e612620565b606091505b50909150505b6005546040516370a0823160e01b81526001600160a01b03868116600483015260009216906370a0823190602401602060405180830381865afa158015612671573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126959190614116565b90508115806126ad57506126a984846142a0565b8114155b156126cb5760405163da67ce5960e01b815260040160405180910390fd5b5050505050565b60006126dd83611a25565b6001600160a01b038416600090815260036020526040902042600490910155905061270882826142a0565b6001600160a01b039093166000908152600360205260409020600701929092555050565b805160005b61273c6001836142a0565b811015610ca85760006127508260016142b3565b90505b828110156127d15783818151811061276d5761276d6140d1565b60200260200101516001600160a01b0316848381518110612790576127906140d1565b60200260200101516001600160a01b0316036127bf57604051636e7c990560e01b815260040160405180910390fd5b806127c9816140fd565b915050612753565b50806127dc816140fd565b915050612731565b825184511415806127f757508151845114155b1561281557604051633f4e2f2960e21b815260040160405180910390fd5b6000805b8551811015612a085760096000878381518110612838576128386140d1565b6020908102919091018101516001600160a01b0316825281019190915260400160009081205460ff161515900361288257604051635cfb665160e01b815260040160405180910390fd5b858181518110612894576128946140d1565b60200260200101516001600160a01b031663a4cbec738683815181106128bc576128bc6140d1565b6020026020010151896128ce8b611f13565b8886815181106128e0576128e06140d1565b60200260200101518d6040516020016128f9919061412f565b6040516020818303038152906040526040518663ffffffff1660e01b815260040161292794939291906141bf565b60206040518083038185885af1158015612945573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061296a9190614116565b5087608001517f5a94fe36b9c96bbd30dafe9eb364e4d1ac0751c6f8c114bd0977952694149c078783815181106129a3576129a36140d1565b60200260200101516040516129c791906001600160a01b0391909116815260200190565b60405180910390a28481815181106129e1576129e16140d1565b6020026020010151826129f491906142b3565b915080612a00816140fd565b915050612819565b508181146111b65760405163c0a890d760e01b815260040160405180910390fd5b612a3161340b565b6001805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b83838114612aed574260025484612a9291906142b3565b11612a9e575082612aed565b4260025484612aad91906142b3565b1115612aed576000612abf84426142a0565b90506000612acd84836142c6565b612ad790846142b3565b9050858111612ae65780612ae8565b855b925050505b949350505050565b6000612b00836114a0565b6001600160a01b03841660009081526003602052604090204290559050612b2782826142a0565b6001600160a01b03909316600090815260036020819052604090912001929092555050565b60055460408051600481526024810182526020810180516001600160e01b03166333662b8160e11b179052905160009283926001600160a01b0390911691612b949190614284565b6000604051808303816000865af19150503d8060008114612bd1576040519150601f19603f3d011682016040523d82523d6000602084013e612bd6565b606091505b5091509150818015612be85750805115155b15612ffc57600081806020019051810190612c0391906142dd565b90506001600160a01b03811615612ffa576005546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015612c5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c819190614116565b9050612c8d3086613002565b6005546040516370a0823160e01b815230600482015260009183916001600160a01b03909116906370a0823190602401602060405180830381865afa158015612cda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cfe9190614116565b612d0891906142a0565b60408051600481526024810182526020810180516001600160e01b0316633312a88160e21b179052905191925060009182916001600160a01b03871691612d4f9190614284565b6000604051808303816000865af19150503d8060008114612d8c576040519150601f19603f3d011682016040523d82523d6000602084013e612d91565b606091505b506005546040516001600160a01b03898116602483015260448201889052939550919350919091169060640160408051601f198184030181529181526020820180516001600160e01b031663095ea7b360e01b17905251612df29190614284565b6000604051808303816000865af19150503d8060008114612e2f576040519150601f19603f3d011682016040523d82523d6000602084013e612e34565b606091505b5090975050861580612e44575081155b80612ec05750600554604051636eb1769f60e11b81523060048201526001600160a01b0387811660248301528592169063dd62ed3e90604401602060405180830381865afa158015612e9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ebe9190614116565b105b15612ee757600554612edc906001600160a01b03168a85613454565b505050505050505050565b600081806020019051810190612efd91906142dd565b90506001600160a01b038116612f3057600554612f24906001600160a01b03168b86613454565b50505050505050505050565b856001600160a01b031684604051602401612f4d91815260200190565b60408051601f198184030181529181526020820180516001600160e01b0316632e1a7d4d60e01b17905251612f829190614284565b6000604051808303816000865af19150503d8060008114612fbf576040519150601f19603f3d011682016040523d82523d6000602084013e612fc4565b606091505b50508098505087612fe657600554612f24906001600160a01b03168b86613454565b612f246001600160a01b0382168b86613454565b505b610c7d84845b6005546040516001600160a01b0384811660248301526044820184905260009216907f00000000000000000000000000000000000000000000000000000000000000009060640160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516130879190614284565b6000604051808303816000865af19150503d80600081146130c4576040519150601f19603f3d011682016040523d82523d6000602084013e6130c9565b606091505b5050905080610ca857604051638d938d7b60e01b815260040160405180910390fd5b6130f36121ef565b6001805460ff1916811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833612a5e565b61313360026000196142fa565b82118061314b575061314860026000196142fa565b81115b15613169576040516301e8cafb60e71b815260040160405180910390fd5b6131738383613484565b61317d8382613529565b60408051838152602081018390526001600160a01b038516917f93f3bbfe8cfb354ec059175107653f49f6eb479a8622a7d83866ea015435c9449101610b3f565b80518251146131e057604051633f4e2f2960e21b815260040160405180910390fd5b60005b8251811015610ca8578181815181106131fe576131fe6140d1565b60200260200101516008600085848151811061321c5761321c6140d1565b6020026020010151815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550818181518110613268576132686140d1565b60200260200101516001600160a01b03167f3083b3b95a46df5c4a6cdd1fa242b76f968ed75bf364ec15de70e5b043f628318483815181106132ac576132ac6140d1565b60200260200101516040516132c391815260200190565b60405180910390a2806132d5816140fd565b9150506131e3565b6132e782826119fc565b610d2c576132f4816135d3565b6132ff8360206135e5565b60405160200161331092919061431c565b60408051601f198184030181529082905262461bcd60e51b8252610d1991600401614391565b600061338b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137879092919063ffffffff16565b90508051600014806133ac5750808060200190518101906133ac91906143a4565b610ca85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610d19565b60015460ff166122355760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610d19565b6040516001600160a01b038316602482015260448101829052610ca890849063a9059cbb60e01b9060640161226b565b6001600160a01b038216600090815260036020526040812060020154906134aa846114a0565b6001600160a01b038516600090815260036020526040902060020184905590506134d5838383613796565b6001600160a01b038516600090815260036020819052604090912001556002546134ff90846142fa565b6001600160a01b039094166000908152600360205260409020600181019490945550504290915550565b6001600160a01b0382166000908152600360205260408120600601549061354f84611a25565b6001600160a01b0385166000908152600360205260409020600601849055905061357a838383613796565b6001600160a01b0385166000908152600360205260409020600701556002546135a390846142fa565b6001600160a01b039094166000908152600360205260409020600581019490945550504260049092019190915550565b6060610ae26001600160a01b03831660145b606060006135f48360026142c6565b6135ff9060026142b3565b6001600160401b0381111561361657613616613a2e565b6040519080825280601f01601f191660200182016040528015613640576020820181803683370190505b509050600360fc1b8160008151811061365b5761365b6140d1565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061368a5761368a6140d1565b60200101906001600160f81b031916908160001a90535060006136ae8460026142c6565b6136b99060016142b3565b90505b6001811115613731576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106136ed576136ed6140d1565b1a60f81b828281518110613703576137036140d1565b60200101906001600160f81b031916908160001a90535060049490941c9361372a816143c1565b90506136bc565b5083156137805760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610d19565b9392505050565b6060612aed84846000856137ed565b600080848411156137cc576137ab85856142a0565b90508083116137bb5760006137c5565b6137c581846142a0565b91506137e5565b6137d684866142a0565b90506137e281846142b3565b91505b509392505050565b60608247101561384e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610d19565b600080866001600160a01b0316858760405161386a9190614284565b60006040518083038185875af1925050503d80600081146138a7576040519150601f19603f3d011682016040523d82523d6000602084013e6138ac565b606091505b5091509150612ae88783838760608315613927578251600003613920576001600160a01b0385163b6139205760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d19565b5081612aed565b612aed838381511561393c5781518083602001fd5b8060405162461bcd60e51b8152600401610d199190614391565b60006020828403121561396857600080fd5b5035919050565b60006020828403121561398157600080fd5b81356001600160e01b03198116811461378057600080fd5b6001600160a01b03811681146111f157600080fd5b6000602082840312156139c057600080fd5b813561378081613999565b80151581146111f157600080fd5b600080604083850312156139ec57600080fd5b8235915060208301356139fe816139cb565b809150509250929050565b60008060408385031215613a1c57600080fd5b8235915060208301356139fe81613999565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613a6c57613a6c613a2e565b604052919050565b60006001600160401b03821115613a8d57613a8d613a2e565b5060051b60200190565b600082601f830112613aa857600080fd5b81356020613abd613ab883613a74565b613a44565b82815260059290921b84018101918181019086841115613adc57600080fd5b8286015b84811015613b00578035613af381613999565b8352918301918301613ae0565b509695505050505050565b60008060408385031215613b1e57600080fd5b82356001600160401b0380821115613b3557600080fd5b613b4186838701613a97565b9350602091508185013581811115613b5857600080fd5b85019050601f81018613613b6b57600080fd5b8035613b79613ab882613a74565b81815260059190911b82018301908381019088831115613b9857600080fd5b928401925b82841015613bbf578335613bb0816139cb565b82529284019290840190613b9d565b80955050505050509250929050565b600060208284031215613be057600080fd5b8135613780816139cb565b600082601f830112613bfc57600080fd5b81356020613c0c613ab883613a74565b82815260059290921b84018101918181019086841115613c2b57600080fd5b8286015b84811015613b005780358352918301918301613c2f565b600082601f830112613c5757600080fd5b81356001600160401b03811115613c7057613c70613a2e565b613c83601f8201601f1916602001613a44565b818152846020838601011115613c9857600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f830112613cc657600080fd5b81356020613cd6613ab883613a74565b82815260059290921b84018101918181019086841115613cf557600080fd5b8286015b84811015613b005780356001600160401b03811115613d185760008081fd5b613d268986838b0101613c46565b845250918301918301613cf9565b600080600080600080600060e0888a031215613d4f57600080fd5b8735613d5a81613999565b9650602088013595506040880135613d71816139cb565b94506060880135935060808801356001600160401b0380821115613d9457600080fd5b613da08b838c01613a97565b945060a08a0135915080821115613db657600080fd5b613dc28b838c01613beb565b935060c08a0135915080821115613dd857600080fd5b50613de58a828b01613cb5565b91505092959891949750929550565b600080600060608486031215613e0957600080fd5b833592506020840135613e1b81613999565b915060408401356001600160401b03811115613e3657600080fd5b613e4286828701613c46565b9150509250925092565b60008060008060608587031215613e6257600080fd5b84356001600160401b0380821115613e7957600080fd5b818701915087601f830112613e8d57600080fd5b813581811115613e9c57600080fd5b886020828501011115613eae57600080fd5b6020928301965094505085013591506040850135613ecb81613999565b939692955090935050565b600080600060608486031215613eeb57600080fd5b8335613ef681613999565b95602085013595506040909401359392505050565b60008060408385031215613f1e57600080fd5b82356001600160401b0380821115613f3557600080fd5b613f4186838701613beb565b93506020850135915080821115613f5757600080fd5b50613f6485828601613a97565b9150509250929050565b82518152602080840151818301526040808501518184015260608086015181850152845160808501529184015160a084015283015160c083015282015160e08201526101008101613780565b60008060008060008060c08789031215613fd357600080fd5b8635613fde81613999565b9550602087013594506040870135613ff5816139cb565b935060608701359250608087013561400c81613999565b915060a08701356001600160401b0381111561402757600080fd5b61403389828a01613c46565b9150509295509295509295565b6000806000806080858703121561405657600080fd5b8435935060208501356001600160401b038082111561407457600080fd5b61408088838901613a97565b9450604087013591508082111561409657600080fd5b6140a288838901613beb565b935060608701359150808211156140b857600080fd5b506140c587828801613cb5565b91505092959194509250565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161410f5761410f6140e7565b5060010190565b60006020828403121561412857600080fd5b5051919050565b81516001600160a01b0316815260208083015190820152604080830151151590820152606080830151908201526080918201519181019190915260a00190565b60005b8381101561418a578181015183820152602001614172565b50506000910152565b600081518084526141ab81602086016020860161416f565b601f01601f19169290920160200192915050565b8481526001600160a01b03841660208201526080604082018190526000906141e990830185614193565b82810360608401526141fb8185614193565b979650505050505050565b600060a0828403121561421857600080fd5b60405160a081018181106001600160401b038211171561423a5761423a613a2e565b604052823561424881613999565b8152602083810135908201526040830135614262816139cb565b6040820152606083810135908201526080928301359281019290925250919050565b6000825161429681846020870161416f565b9190910192915050565b81810381811115610ae257610ae26140e7565b80820180821115610ae257610ae26140e7565b8082028115828204841417610ae257610ae26140e7565b6000602082840312156142ef57600080fd5b815161378081613999565b60008261431757634e487b7160e01b600052601260045260246000fd5b500490565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161435481601785016020880161416f565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161438581602884016020880161416f565b01602801949350505050565b6020815260006137806020830184614193565b6000602082840312156143b657600080fd5b8151613780816139cb565b6000816143d0576143d06140e7565b50600019019056fea264697066735822122014555f41f27d588b1fdd35163b5e30a50cb4cb9721ea9ab185fb14f5b2e8b1c464736f6c63430008130033139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d000000000000000000000000909583f64948e4c6a9c7a9285c292e9d9302fb960000000000000000000000005db7ad07d4903579a0342f7332bd4e3ed480d1af0000000000000000000000005db7ad07d4903579a0342f7332bd4e3ed480d1af0000000000000000000000002ff4e5ff77e49eba45bffea2f75814d114f9c90400000000000000000000000051b206899bcfcbf4530412a43ed5c2336f91c90c0000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000004e000000000000000000000000000000000000000000000000000000000000005a040c10f190000000000000000000000000000000000000000000000000000000042966c6800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000a4b1000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000002105000000000000000000000000000000000000000000000000000000000000e7080000000000000000000000000000000000000000000000000000000000013e3100000000000000000000000000000000000000000000000000000000000000890000000000000000000000000000000000000000000000000000000000000d0a000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000138de0000000000000000000000000000000000000000000000000000000000001388000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000df00000000000000000000000000000000000000000000000000000000000182320000000000000000000000000000000000000000000000000000000000000005000000000000000000000000cb8530f2b20f3c62602f01d3a78bcc58e9aea8530000000000000000000000005ef37628d45c80740fb6db7ed9c0a753b4f85263000000000000000000000000a9bd5559531fe372e866ad4337599962d5810e010000000000000000000000000ea1c09b884dc5758ed1d9bd006dceb20d31c439000000000000000000000000dea0243b5ee5200d1feba615eaa7385598417b8600000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce800000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Deployed Bytecode
0x6080604052600436106102805760003560e01c80637385e7fb1161014f578063c1eb7137116100c1578063d3a8b6311161007a578063d3a8b63114610a08578063d547741f14610a1b578063d6991b5b14610a3b578063e751f27114610a5b578063eab6995814610a7b578063fc0c546a14610a9157600080fd5b8063c1eb713714610898578063c415b95c146108d1578063cdf0366f1461091d578063ced67f0c1461093d578063d236ad68146109d5578063d30a41c8146109f557600080fd5b806391d148541161011357806391d148541461075f578063968638861461077f578063998955d31461082d578063a08d56541461084d578063a217fddf1461086d578063affed0e01461088257600080fd5b80637385e7fb1461066c5780637e0a8c6a1461069c5780638456cb59146106f557806387a131bb1461070a57806389a3b4fb1461073e57600080fd5b806336568abe116101f357806351cff8d9116101ac57806351cff8d914610587578063544fe464146105a75780635c975abb146105f4578063651fd2681461060c5780637256d8721461062c578063734afa2b1461064c57600080fd5b806336568abe146104d8578063365fc213146104f8578063389ed2671461051857806339c82de61461054c5780633f4ba83a1461055f5780634995c3e71461057457600080fd5b806315af3b671161024557806315af3b671461036d5780631f9bb777146103a8578063215e73e114610438578063248a9ca31461046857806327a65d3f146104985780632f2ff15d146104b857600080fd5b80625856cb1461028c57806301ffc9a7146102cc5780630c05f82c146102fc5780630fb5a6b41461033557806312ca7dbb1461034b57600080fd5b3661028757005b600080fd5b34801561029857600080fd5b506102b96102a7366004613956565b600d6020526000908152604090205481565b6040519081526020015b60405180910390f35b3480156102d857600080fd5b506102ec6102e736600461396f565b610ab1565b60405190151581526020016102c3565b34801561030857600080fd5b506102b96103173660046139ae565b6001600160a01b031660009081526003602052604090206002015490565b34801561034157600080fd5b506102b960025481565b34801561035757600080fd5b5061036b6103663660046139d9565b610ae8565b005b34801561037957600080fd5b506102ec610388366004613a09565b600e60209081526000928352604080842090915290825290205460ff1681565b3480156103b457600080fd5b506104006103c3366004613956565b600c60205260009081526040902080546001820154600283015460038401546004909401546001600160a01b0390931693919260ff909116919085565b604080516001600160a01b0390961686526020860194909452911515928401929092526060830191909152608082015260a0016102c3565b34801561044457600080fd5b506102ec6104533660046139ae565b60096020526000908152604090205460ff1681565b34801561047457600080fd5b506102b9610483366004613956565b60009081526020819052604090206001015490565b3480156104a457600080fd5b5061036b6104b3366004613b0b565b610b4c565b3480156104c457600080fd5b5061036b6104d3366004613a09565b610c83565b3480156104e457600080fd5b5061036b6104f3366004613a09565b610cad565b34801561050457600080fd5b5061036b610513366004613bce565b610d30565b34801561052457600080fd5b506102b97f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d81565b61036b61055a366004613d34565b610d94565b34801561056b57600080fd5b5061036b6111bf565b61036b610582366004613df4565b6111f4565b34801561059357600080fd5b5061036b6105a23660046139ae565b6113fa565b3480156105b357600080fd5b506105db7f40c10f190000000000000000000000000000000000000000000000000000000081565b6040516001600160e01b031990911681526020016102c3565b34801561060057600080fd5b5060015460ff166102ec565b34801561061857600080fd5b506102b96106273660046139ae565b6114a0565b34801561063857600080fd5b506102b9610647366004613956565b6114d5565b34801561065857600080fd5b5061036b610667366004613e4c565b61151c565b34801561067857600080fd5b506102ec610687366004613956565b600a6020526000908152604090205460ff1681565b3480156106a857600080fd5b5060408051808201909152600d81526c6275726e2875696e743235362960981b6020909101526105db7f42966c689b5afe9b9b3f8a7103b2a19980d59629bfd6a20a60972312ed41d83681565b34801561070157600080fd5b5061036b6119ca565b34801561071657600080fd5b506105db7f42966c680000000000000000000000000000000000000000000000000000000081565b34801561074a57600080fd5b506005546102ec90600160a01b900460ff1681565b34801561076b57600080fd5b506102ec61077a366004613a09565b6119fc565b34801561078b57600080fd5b506107e661079a366004613956565b600b6020526000908152604090208054600182015460028301546003840154600485015460058601546006909601546001600160a01b0390951695939460ff9384169492939192911687565b604080516001600160a01b0390981688526020880196909652931515948601949094526060850191909152608084015260a0830191909152151560c082015260e0016102c3565b34801561083957600080fd5b506102b96108483660046139ae565b611a25565b34801561085957600080fd5b5061036b610868366004613ed6565b611a5c565b34801561087957600080fd5b506102b9600081565b34801561088e57600080fd5b506102b960075481565b3480156108a457600080fd5b506102b96108b33660046139ae565b6001600160a01b031660009081526003602052604090206006015490565b3480156108dd57600080fd5b506109057f0000000000000000000000002ff4e5ff77e49eba45bffea2f75814d114f9c90481565b6040516001600160a01b0390911681526020016102c3565b34801561092957600080fd5b5061036b610938366004613f0b565b611a72565b34801561094957600080fd5b506109c76109583660046139ae565b60036020818152600092835260409283902083516080808201865282548252600183015482850152600283015482870152938201546060808301919091528551948501865260048301548552600583015493850193909352600682015494840194909452600701549082015282565b6040516102c3929190613f6e565b3480156109e157600080fd5b5061036b6109f0366004613956565b611a87565b61036b610a03366004613fba565b611ac7565b61036b610a16366004614040565b611db9565b348015610a2757600080fd5b5061036b610a36366004613a09565b611eee565b348015610a4757600080fd5b50610905610a56366004613956565b611f13565b348015610a6757600080fd5b5061036b610a76366004613956565b611f2e565b348015610a8757600080fd5b506102b960065481565b348015610a9d57600080fd5b50600554610905906001600160a01b031681565b60006001600160e01b03198216637965db0b60e01b1480610ae257506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000610af3816120a3565b6000838152600a6020908152604091829020805460ff1916851515908117909155915191825284917f8670d56066b58d6b5eff6e9ff63fb7bc28c6d4ec9676c45cf2360314e9e9c24a91015b60405180910390a2505050565b6000610b57816120a3565b8151835114610b7957604051633f4e2f2960e21b815260040160405180910390fd5b60005b8351811015610c7d57828181518110610b9757610b976140d1565b602002602001015160096000868481518110610bb557610bb56140d1565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550838181518110610c0657610c066140d1565b60200260200101516001600160a01b03167fd3577f4d8ca054ac85e150e2a592220c54234d070e9f8ed0199869b7a17b2520848381518110610c4a57610c4a6140d1565b6020026020010151604051610c63911515815260200190565b60405180910390a280610c75816140fd565b915050610b7c565b50505050565b600082815260208190526040902060010154610c9e816120a3565b610ca883836120ad565b505050565b6001600160a01b0381163314610d225760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610d2c8282612131565b5050565b6000610d3b816120a3565b60058054831515600160a01b0260ff60a01b199091161790556040517f2b777c07ea46054410835bc43625d87926c44d9a6b4ec49a7e3248d434cfe5b590610d8890841515815260200190565b60405180910390a15050565b610d9c612196565b610da46121ef565b85600003610dc557604051636c13c71b60e01b815260040160405180910390fd5b604051633b46f5db60e21b8152600481018790526000907f0000000000000000000000002ff4e5ff77e49eba45bffea2f75814d114f9c9046001600160a01b03169063ed1bd76c90602401602060405180830381865afa158015610e2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e519190614116565b90508015610f3057610e71336005546001600160a01b0316903084612237565b600554610ea8906001600160a01b03167f0000000000000000000000002ff4e5ff77e49eba45bffea2f75814d114f9c904836122a2565b600554604051631ae0d5eb60e21b81526001600160a01b039182166004820152602481018390527f0000000000000000000000002ff4e5ff77e49eba45bffea2f75814d114f9c90490911690636b8357ac90604401600060405180830381600087803b158015610f1757600080fd5b505af1158015610f2b573d6000803e3d6000fd5b505050505b610f3a33886123b7565b6000610f466000611a25565b905087811015610f6957604051633ebc3cb560e11b815260040160405180910390fd5b610f746000896126d2565b610f7d8561272c565b60065485511015610fa157604051633f4e2f2960e21b815260040160405180910390fd5b6001600160a01b038916610fc857604051633f4e2f2960e21b815260040160405180910390fd5b600654600003610feb5760405163d123a59d60e01b815260040160405180910390fd5b6000610ff687611f13565b6001600160a01b03160361101d57604051634ea9399d60e01b815260040160405180910390fd5b6000868152600a602052604090205460ff161561104d5760405163e5d48ceb60e01b815260040160405180910390fd5b6000611058876114d5565b60078054919250600061106a836140fd565b919050555060006040518060a001604052808c6001600160a01b031681526020018b81526020018a15158152602001600654815260200183815250905087600d60008481526020019081526020016000208190555080600c600084815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506020820151816001015560408201518160020160006101000a81548160ff021916908315150217905550606082015181600301556080820151816004015590505061114f8189898989346127e4565b600654604080519182526001600160a01b038d16602083015281018b905289151560608201523390899084907f7214d2a3fc41a2bc94a7a69749a3d127afd8d8e79e0573dbe7892d84ee6fdd749060800160405180910390a4505050506111b66001600455565b50505050505050565b7f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d6111e9816120a3565b6111f1612a29565b50565b6111fc612196565b6112046121ef565b6000838152600d6020526040812054908190036112345760405163789d685360e01b815260040160405180910390fd5b6000848152600c6020908152604091829020825160a08101845281546001600160a01b0316815260018083015493820193909352600282015460ff16151593810193909352600381015460608401819052600490910154608084015290036113d55760006112a185611a25565b905081602001518110156112c857604051633ebc3cb560e11b815260040160405180910390fd5b846001600160a01b031663a4cbec7334856112e287611f13565b88876040516020016112f4919061412f565b6040516020818303038152906040526040518663ffffffff1660e01b815260040161132294939291906141bf565b60206040518083038185885af1158015611340573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906113659190614116565b5060405186907fdc2df65ad98a3640553c4a6fa9e8b28b7cac67002cff20bfa132ad69b51b9e6d90600090a26040516001600160a01b038616815286907f5a94fe36b9c96bbd30dafe9eb364e4d1ac0751c6f8c114bd0977952694149c079060200160405180910390a2506113ee565b604051633f4e2f2960e21b815260040160405180910390fd5b5050610ca86001600455565b6000611405816120a3565b6001600160a01b03821661142c57604051633f4e2f2960e21b815260040160405180910390fd5b6000826001600160a01b03164760405160006040518083038185875af1925050503d8060008114611479576040519150601f19603f3d011682016040523d82523d6000602084013e61147e565b606091505b5050905080610ca857604051631bc19cc560e31b815260040160405180910390fd5b6001600160a01b038116600090815260036020819052604082209081015460028201548254600190930154610ae29390612a7b565b600081466007546040516020016114ff939291909283526020830191909152604082015260600190565b604051602081830303815290604052805190602001209050919050565b611524612196565b61152c6121ef565b806001600160a01b031661153f83611f13565b6001600160a01b03161461156657604051633f4e2f2960e21b815260040160405180910390fd5b600061157484860186614206565b905080606001516001036117325760808101516000908152600b6020526040902060010154156115b757604051632da0ab1960e01b815260040160405180910390fd5b6040805160e08101825282516001600160a01b039081168252602080850151818401908152858501511515848601908152600160608601818152608080880183815260a089018d815260c08a01858152928c01516000908152600b9098529987209851895498166001600160a01b0319909816979097178855935191870191909155905160028601805491151560ff1992831617905590516003860155925160048501559351600584015592516006909201805492151592909116919091179055611681336114a0565b905081602001518110156116a857604051633ebc3cb560e11b815260040160405180910390fd5b6116b6338360200151612af5565b816040015180156116d05750600554600160a01b900460ff165b156116ec576116e782600001518360200151612b4c565b6116fe565b6116fe82600001518360200151613002565b60808201516040517fe843a2101c5af088cd2648db06f117411c38047d50a9f499f99cd99adb41490a90600090a250611982565b3360009081526009602052604090205460ff1661176257604051635cfb665160e01b815260040160405180910390fd5b60808101516000908152600e6020908152604080832033845290915290205460ff1615156001036117a65760405163c7d1b4c160e01b815260040160405180910390fd5b608080820180516000908152600e602090815260408083203384528252808320805460ff1916600190811790915593518352600b8252808320815160e08101835281546001600160a01b031681529481015492850192909252600282015460ff908116151591850191909152600382015460608501819052600483015495850195909552600582015460a085015260069091015416151560c0830152909190036118a3576040518060e0016040528083600001516001600160a01b031681526020018360200151815260200183604001511515815260200160018152602001836060015181526020018581526020016000151581525090506118b7565b606081018051906118b3826140fd565b9052505b80608001518160600151106118f55760808201516040517fb23e240f843ae6fd7bc9d43aef3333ff0333d69a51e80b0d869df7546162622590600090a25b6080808301516000908152600b6020908152604091829020845181546001600160a01b039091166001600160a01b03199091161781559084015160018201559083015160028201805491151560ff199283161790556060840151600383015591830151600482015560a0830151600582015560c09092015160069092018054921515929091169190911790555b6080810151604080518581523360208201527fb56eee7198c2db26c3593517941abaa02608050011d356b4f29e8a5c6a269aed910160405180910390a250610c7d6001600455565b7f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d6119f4816120a3565b6111f16130eb565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6001600160a01b0381166000908152600360205260408120600781015460068201546004830154600590930154610ae29390612a7b565b6000611a67816120a3565b610c7d848484613126565b6000611a7d816120a3565b610ca883836131be565b6000611a92816120a3565b60068290556040518281527fe125065bd51f3e795dd066e6f64e43cedd27dc38adf0062c7be9eaa209ae114790602001610d88565b611acf612196565b611ad76121ef565b84600003611af857604051636c13c71b60e01b815260040160405180910390fd5b84611b0283611a25565b1015611b2157604051633ebc3cb560e11b815260040160405180910390fd5b611b2b82866126d2565b611b3533866123b7565b6001600160a01b038616611b5c57604051633f4e2f2960e21b815260040160405180910390fd5b6000611b6784611f13565b6001600160a01b031603611b8e57604051634ea9399d60e01b815260040160405180910390fd5b6000838152600a602052604090205460ff1615611bbe5760405163e5d48ceb60e01b815260040160405180910390fd5b6000611bc9846114d5565b600780549192506000611bdb836140fd565b90915550506000818152600d60209081526040808320879055805160a0810182526001600160a01b038b811682528184018b81528a1515838501908152600160608501818152608086018a81528a8a52600c90985295909720845181546001600160a01b031916908516178155915196820196909655945160028601805460ff191691151591909117905591516003850155915160049093019290925590841663a4cbec733487611c8b81611f13565b8786604051602001611c9d919061412f565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611ccb94939291906141bf565b60206040518083038185885af1158015611ce9573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611d0e9190614116565b5060408051600181526001600160a01b038a166020820152808201899052871515606082015290513391879185917f7214d2a3fc41a2bc94a7a69749a3d127afd8d8e79e0573dbe7892d84ee6fdd74919081900360800190a46040516001600160a01b038516815282907f5a94fe36b9c96bbd30dafe9eb364e4d1ac0751c6f8c114bd0977952694149c079060200160405180910390a25050611db16001600455565b505050505050565b611dc1612196565b611dc96121ef565b6000848152600d602052604081205490819003611df95760405163789d685360e01b815260040160405180910390fd5b600654600003611e1c5760405163d123a59d60e01b815260040160405180910390fd5b611e258461272c565b6000858152600c6020908152604091829020825160a08101845281546001600160a01b0316815260018083015493820193909352600282015460ff16151593810193909352600381015460608401819052600490910154608084015211156113d5578351855114611ea957604051633f4e2f2960e21b815260040160405180910390fd5b611eb78183878787346127e4565b60405186907fdc2df65ad98a3640553c4a6fa9e8b28b7cac67002cff20bfa132ad69b51b9e6d90600090a25050610c7d6001600455565b600082815260208190526040902060010154611f09816120a3565b610ca88383612131565b6000908152600860205260409020546001600160a01b031690565b611f36612196565b611f3e6121ef565b6000818152600b602052604081206001810154909103611f715760405163789d685360e01b815260040160405180910390fd5b600681015460ff1615611f9757604051632da0ab1960e01b815260040160405180910390fd5b806004015481600301541015611fc057604051631b8d5dc160e01b815260040160405180910390fd5b6000611fcc60006114a0565b90508160010154811015611ff357604051633ebc3cb560e11b815260040160405180910390fd5b61200260008360010154612af5565b60068201805460ff19166001179055600282015460ff16801561202e5750600554600160a01b900460ff165b15612052578154600183015461204d916001600160a01b031690612b4c565b61206c565b8154600183015461206c916001600160a01b031690613002565b60405183907fe843a2101c5af088cd2648db06f117411c38047d50a9f499f99cd99adb41490a90600090a250506111f16001600455565b6111f181336132dd565b6120b782826119fc565b610d2c576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556120ed3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b61213b82826119fc565b15610d2c576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6002600454036121e85760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d19565b6002600455565b60015460ff16156122355760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610d19565b565b6040516001600160a01b0380851660248301528316604482015260648101829052610c7d9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613336565b80158061231c5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156122f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231a9190614116565b155b6123875760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610d19565b6040516001600160a01b038316602482015260448101829052610ca890849063095ea7b360e01b9060640161226b565b6005546040516370a0823160e01b81526001600160a01b03848116600483015260009216906370a0823190602401602060405180830381865afa158015612402573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124269190614116565b60408051808201909152600d81526c6275726e2875696e743235362960981b602090910152905060006317ad327360e31b7f42966c68000000000000000000000000000000000000000000000000000000006001600160e01b031916016125615760055461249f906001600160a01b0316853086612237565b60055460408051602480820187905282518083039091018152604490910182526020810180516001600160e01b03167f42966c68000000000000000000000000000000000000000000000000000000006001600160e01b03191617905290516001600160a01b03909216916125149190614284565b6000604051808303816000865af19150503d8060008114612551576040519150601f19603f3d011682016040523d82523d6000602084013e612556565b606091505b505080915050612626565b600554604080516001600160a01b038781166024830152604480830188905283518084039091018152606490920183526020820180516001600160e01b03167f42966c68000000000000000000000000000000000000000000000000000000006001600160e01b031916179052915191909216916125de91614284565b6000604051808303816000865af19150503d806000811461261b576040519150601f19603f3d011682016040523d82523d6000602084013e612620565b606091505b50909150505b6005546040516370a0823160e01b81526001600160a01b03868116600483015260009216906370a0823190602401602060405180830381865afa158015612671573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126959190614116565b90508115806126ad57506126a984846142a0565b8114155b156126cb5760405163da67ce5960e01b815260040160405180910390fd5b5050505050565b60006126dd83611a25565b6001600160a01b038416600090815260036020526040902042600490910155905061270882826142a0565b6001600160a01b039093166000908152600360205260409020600701929092555050565b805160005b61273c6001836142a0565b811015610ca85760006127508260016142b3565b90505b828110156127d15783818151811061276d5761276d6140d1565b60200260200101516001600160a01b0316848381518110612790576127906140d1565b60200260200101516001600160a01b0316036127bf57604051636e7c990560e01b815260040160405180910390fd5b806127c9816140fd565b915050612753565b50806127dc816140fd565b915050612731565b825184511415806127f757508151845114155b1561281557604051633f4e2f2960e21b815260040160405180910390fd5b6000805b8551811015612a085760096000878381518110612838576128386140d1565b6020908102919091018101516001600160a01b0316825281019190915260400160009081205460ff161515900361288257604051635cfb665160e01b815260040160405180910390fd5b858181518110612894576128946140d1565b60200260200101516001600160a01b031663a4cbec738683815181106128bc576128bc6140d1565b6020026020010151896128ce8b611f13565b8886815181106128e0576128e06140d1565b60200260200101518d6040516020016128f9919061412f565b6040516020818303038152906040526040518663ffffffff1660e01b815260040161292794939291906141bf565b60206040518083038185885af1158015612945573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061296a9190614116565b5087608001517f5a94fe36b9c96bbd30dafe9eb364e4d1ac0751c6f8c114bd0977952694149c078783815181106129a3576129a36140d1565b60200260200101516040516129c791906001600160a01b0391909116815260200190565b60405180910390a28481815181106129e1576129e16140d1565b6020026020010151826129f491906142b3565b915080612a00816140fd565b915050612819565b508181146111b65760405163c0a890d760e01b815260040160405180910390fd5b612a3161340b565b6001805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b83838114612aed574260025484612a9291906142b3565b11612a9e575082612aed565b4260025484612aad91906142b3565b1115612aed576000612abf84426142a0565b90506000612acd84836142c6565b612ad790846142b3565b9050858111612ae65780612ae8565b855b925050505b949350505050565b6000612b00836114a0565b6001600160a01b03841660009081526003602052604090204290559050612b2782826142a0565b6001600160a01b03909316600090815260036020819052604090912001929092555050565b60055460408051600481526024810182526020810180516001600160e01b03166333662b8160e11b179052905160009283926001600160a01b0390911691612b949190614284565b6000604051808303816000865af19150503d8060008114612bd1576040519150601f19603f3d011682016040523d82523d6000602084013e612bd6565b606091505b5091509150818015612be85750805115155b15612ffc57600081806020019051810190612c0391906142dd565b90506001600160a01b03811615612ffa576005546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015612c5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c819190614116565b9050612c8d3086613002565b6005546040516370a0823160e01b815230600482015260009183916001600160a01b03909116906370a0823190602401602060405180830381865afa158015612cda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cfe9190614116565b612d0891906142a0565b60408051600481526024810182526020810180516001600160e01b0316633312a88160e21b179052905191925060009182916001600160a01b03871691612d4f9190614284565b6000604051808303816000865af19150503d8060008114612d8c576040519150601f19603f3d011682016040523d82523d6000602084013e612d91565b606091505b506005546040516001600160a01b03898116602483015260448201889052939550919350919091169060640160408051601f198184030181529181526020820180516001600160e01b031663095ea7b360e01b17905251612df29190614284565b6000604051808303816000865af19150503d8060008114612e2f576040519150601f19603f3d011682016040523d82523d6000602084013e612e34565b606091505b5090975050861580612e44575081155b80612ec05750600554604051636eb1769f60e11b81523060048201526001600160a01b0387811660248301528592169063dd62ed3e90604401602060405180830381865afa158015612e9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ebe9190614116565b105b15612ee757600554612edc906001600160a01b03168a85613454565b505050505050505050565b600081806020019051810190612efd91906142dd565b90506001600160a01b038116612f3057600554612f24906001600160a01b03168b86613454565b50505050505050505050565b856001600160a01b031684604051602401612f4d91815260200190565b60408051601f198184030181529181526020820180516001600160e01b0316632e1a7d4d60e01b17905251612f829190614284565b6000604051808303816000865af19150503d8060008114612fbf576040519150601f19603f3d011682016040523d82523d6000602084013e612fc4565b606091505b50508098505087612fe657600554612f24906001600160a01b03168b86613454565b612f246001600160a01b0382168b86613454565b505b610c7d84845b6005546040516001600160a01b0384811660248301526044820184905260009216907f40c10f19000000000000000000000000000000000000000000000000000000009060640160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516130879190614284565b6000604051808303816000865af19150503d80600081146130c4576040519150601f19603f3d011682016040523d82523d6000602084013e6130c9565b606091505b5050905080610ca857604051638d938d7b60e01b815260040160405180910390fd5b6130f36121ef565b6001805460ff1916811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833612a5e565b61313360026000196142fa565b82118061314b575061314860026000196142fa565b81115b15613169576040516301e8cafb60e71b815260040160405180910390fd5b6131738383613484565b61317d8382613529565b60408051838152602081018390526001600160a01b038516917f93f3bbfe8cfb354ec059175107653f49f6eb479a8622a7d83866ea015435c9449101610b3f565b80518251146131e057604051633f4e2f2960e21b815260040160405180910390fd5b60005b8251811015610ca8578181815181106131fe576131fe6140d1565b60200260200101516008600085848151811061321c5761321c6140d1565b6020026020010151815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550818181518110613268576132686140d1565b60200260200101516001600160a01b03167f3083b3b95a46df5c4a6cdd1fa242b76f968ed75bf364ec15de70e5b043f628318483815181106132ac576132ac6140d1565b60200260200101516040516132c391815260200190565b60405180910390a2806132d5816140fd565b9150506131e3565b6132e782826119fc565b610d2c576132f4816135d3565b6132ff8360206135e5565b60405160200161331092919061431c565b60408051601f198184030181529082905262461bcd60e51b8252610d1991600401614391565b600061338b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166137879092919063ffffffff16565b90508051600014806133ac5750808060200190518101906133ac91906143a4565b610ca85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610d19565b60015460ff166122355760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610d19565b6040516001600160a01b038316602482015260448101829052610ca890849063a9059cbb60e01b9060640161226b565b6001600160a01b038216600090815260036020526040812060020154906134aa846114a0565b6001600160a01b038516600090815260036020526040902060020184905590506134d5838383613796565b6001600160a01b038516600090815260036020819052604090912001556002546134ff90846142fa565b6001600160a01b039094166000908152600360205260409020600181019490945550504290915550565b6001600160a01b0382166000908152600360205260408120600601549061354f84611a25565b6001600160a01b0385166000908152600360205260409020600601849055905061357a838383613796565b6001600160a01b0385166000908152600360205260409020600701556002546135a390846142fa565b6001600160a01b039094166000908152600360205260409020600581019490945550504260049092019190915550565b6060610ae26001600160a01b03831660145b606060006135f48360026142c6565b6135ff9060026142b3565b6001600160401b0381111561361657613616613a2e565b6040519080825280601f01601f191660200182016040528015613640576020820181803683370190505b509050600360fc1b8160008151811061365b5761365b6140d1565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061368a5761368a6140d1565b60200101906001600160f81b031916908160001a90535060006136ae8460026142c6565b6136b99060016142b3565b90505b6001811115613731576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106136ed576136ed6140d1565b1a60f81b828281518110613703576137036140d1565b60200101906001600160f81b031916908160001a90535060049490941c9361372a816143c1565b90506136bc565b5083156137805760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610d19565b9392505050565b6060612aed84846000856137ed565b600080848411156137cc576137ab85856142a0565b90508083116137bb5760006137c5565b6137c581846142a0565b91506137e5565b6137d684866142a0565b90506137e281846142b3565b91505b509392505050565b60608247101561384e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610d19565b600080866001600160a01b0316858760405161386a9190614284565b60006040518083038185875af1925050503d80600081146138a7576040519150601f19603f3d011682016040523d82523d6000602084013e6138ac565b606091505b5091509150612ae88783838760608315613927578251600003613920576001600160a01b0385163b6139205760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d19565b5081612aed565b612aed838381511561393c5781518083602001fd5b8060405162461bcd60e51b8152600401610d199190614391565b60006020828403121561396857600080fd5b5035919050565b60006020828403121561398157600080fd5b81356001600160e01b03198116811461378057600080fd5b6001600160a01b03811681146111f157600080fd5b6000602082840312156139c057600080fd5b813561378081613999565b80151581146111f157600080fd5b600080604083850312156139ec57600080fd5b8235915060208301356139fe816139cb565b809150509250929050565b60008060408385031215613a1c57600080fd5b8235915060208301356139fe81613999565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715613a6c57613a6c613a2e565b604052919050565b60006001600160401b03821115613a8d57613a8d613a2e565b5060051b60200190565b600082601f830112613aa857600080fd5b81356020613abd613ab883613a74565b613a44565b82815260059290921b84018101918181019086841115613adc57600080fd5b8286015b84811015613b00578035613af381613999565b8352918301918301613ae0565b509695505050505050565b60008060408385031215613b1e57600080fd5b82356001600160401b0380821115613b3557600080fd5b613b4186838701613a97565b9350602091508185013581811115613b5857600080fd5b85019050601f81018613613b6b57600080fd5b8035613b79613ab882613a74565b81815260059190911b82018301908381019088831115613b9857600080fd5b928401925b82841015613bbf578335613bb0816139cb565b82529284019290840190613b9d565b80955050505050509250929050565b600060208284031215613be057600080fd5b8135613780816139cb565b600082601f830112613bfc57600080fd5b81356020613c0c613ab883613a74565b82815260059290921b84018101918181019086841115613c2b57600080fd5b8286015b84811015613b005780358352918301918301613c2f565b600082601f830112613c5757600080fd5b81356001600160401b03811115613c7057613c70613a2e565b613c83601f8201601f1916602001613a44565b818152846020838601011115613c9857600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f830112613cc657600080fd5b81356020613cd6613ab883613a74565b82815260059290921b84018101918181019086841115613cf557600080fd5b8286015b84811015613b005780356001600160401b03811115613d185760008081fd5b613d268986838b0101613c46565b845250918301918301613cf9565b600080600080600080600060e0888a031215613d4f57600080fd5b8735613d5a81613999565b9650602088013595506040880135613d71816139cb565b94506060880135935060808801356001600160401b0380821115613d9457600080fd5b613da08b838c01613a97565b945060a08a0135915080821115613db657600080fd5b613dc28b838c01613beb565b935060c08a0135915080821115613dd857600080fd5b50613de58a828b01613cb5565b91505092959891949750929550565b600080600060608486031215613e0957600080fd5b833592506020840135613e1b81613999565b915060408401356001600160401b03811115613e3657600080fd5b613e4286828701613c46565b9150509250925092565b60008060008060608587031215613e6257600080fd5b84356001600160401b0380821115613e7957600080fd5b818701915087601f830112613e8d57600080fd5b813581811115613e9c57600080fd5b886020828501011115613eae57600080fd5b6020928301965094505085013591506040850135613ecb81613999565b939692955090935050565b600080600060608486031215613eeb57600080fd5b8335613ef681613999565b95602085013595506040909401359392505050565b60008060408385031215613f1e57600080fd5b82356001600160401b0380821115613f3557600080fd5b613f4186838701613beb565b93506020850135915080821115613f5757600080fd5b50613f6485828601613a97565b9150509250929050565b82518152602080840151818301526040808501518184015260608086015181850152845160808501529184015160a084015283015160c083015282015160e08201526101008101613780565b60008060008060008060c08789031215613fd357600080fd5b8635613fde81613999565b9550602087013594506040870135613ff5816139cb565b935060608701359250608087013561400c81613999565b915060a08701356001600160401b0381111561402757600080fd5b61403389828a01613c46565b9150509295509295509295565b6000806000806080858703121561405657600080fd5b8435935060208501356001600160401b038082111561407457600080fd5b61408088838901613a97565b9450604087013591508082111561409657600080fd5b6140a288838901613beb565b935060608701359150808211156140b857600080fd5b506140c587828801613cb5565b91505092959194509250565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161410f5761410f6140e7565b5060010190565b60006020828403121561412857600080fd5b5051919050565b81516001600160a01b0316815260208083015190820152604080830151151590820152606080830151908201526080918201519181019190915260a00190565b60005b8381101561418a578181015183820152602001614172565b50506000910152565b600081518084526141ab81602086016020860161416f565b601f01601f19169290920160200192915050565b8481526001600160a01b03841660208201526080604082018190526000906141e990830185614193565b82810360608401526141fb8185614193565b979650505050505050565b600060a0828403121561421857600080fd5b60405160a081018181106001600160401b038211171561423a5761423a613a2e565b604052823561424881613999565b8152602083810135908201526040830135614262816139cb565b6040820152606083810135908201526080928301359281019290925250919050565b6000825161429681846020870161416f565b9190910192915050565b81810381811115610ae257610ae26140e7565b80820180821115610ae257610ae26140e7565b8082028115828204841417610ae257610ae26140e7565b6000602082840312156142ef57600080fd5b815161378081613999565b60008261431757634e487b7160e01b600052601260045260246000fd5b500490565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161435481601785016020880161416f565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161438581602884016020880161416f565b01602801949350505050565b6020815260006137806020830184614193565b6000602082840312156143b657600080fd5b8151613780816139cb565b6000816143d0576143d06140e7565b50600019019056fea264697066735822122014555f41f27d588b1fdd35163b5e30a50cb4cb9721ea9ab185fb14f5b2e8b1c464736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000909583f64948e4c6a9c7a9285c292e9d9302fb960000000000000000000000005db7ad07d4903579a0342f7332bd4e3ed480d1af0000000000000000000000005db7ad07d4903579a0342f7332bd4e3ed480d1af0000000000000000000000002ff4e5ff77e49eba45bffea2f75814d114f9c90400000000000000000000000051b206899bcfcbf4530412a43ed5c2336f91c90c0000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000004e000000000000000000000000000000000000000000000000000000000000005a040c10f190000000000000000000000000000000000000000000000000000000042966c6800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000a4b1000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000002105000000000000000000000000000000000000000000000000000000000000e7080000000000000000000000000000000000000000000000000000000000013e3100000000000000000000000000000000000000000000000000000000000000890000000000000000000000000000000000000000000000000000000000000d0a000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000138de0000000000000000000000000000000000000000000000000000000000001388000000000000000000000000000000000000000000000000000000000000009200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000df00000000000000000000000000000000000000000000000000000000000182320000000000000000000000000000000000000000000000000000000000000005000000000000000000000000cb8530f2b20f3c62602f01d3a78bcc58e9aea8530000000000000000000000005ef37628d45c80740fb6db7ed9c0a753b4f85263000000000000000000000000a9bd5559531fe372e866ad4337599962d5810e010000000000000000000000000ea1c09b884dc5758ed1d9bd006dceb20d31c439000000000000000000000000dea0243b5ee5200d1feba615eaa7385598417b8600000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce800000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce80000000000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
-----Decoded View---------------
Arg [0] : _addresses (address[5]): 0x909583f64948e4C6A9c7A9285C292E9d9302fb96,0x5dB7AD07D4903579A0342F7332Bd4E3eD480d1AF,0x5dB7AD07D4903579A0342F7332Bd4E3eD480d1AF,0x2FF4E5Ff77e49ebA45bffEa2F75814d114f9c904,0x51b206899BcFCBf4530412a43ed5C2336f91c90C
Arg [1] : _duration (uint256): 86400
Arg [2] : _minBridges (uint256): 0
Arg [3] : _multiBridgeAdapters (address[]):
Arg [4] : _chainId (uint256[]): 1,42161,10,8453,59144,81457,137,3338,130,80094,5000,146,288,56,100,223,98866
Arg [5] : _bridges (address[]): 0xCB8530f2B20F3c62602f01D3a78BCC58e9aEa853,0x5eF37628d45C80740fb6dB7eD9c0a753b4f85263,0xA9bD5559531fe372E866AD4337599962d5810E01,0x0EA1C09B884dc5758eD1D9Bd006DCeb20d31c439,0xdEA0243b5EE5200d1FEBA615eAa7385598417B86
Arg [6] : _mintingLimits (uint256[]): 1000000000000000000000000000,1000000000000000000000000000,1000000000000000000000000000,1000000000000000000000000000,1000000000000000000000000000
Arg [7] : _burningLimits (uint256[]): 1000000000000000000000000000,1000000000000000000000000000,1000000000000000000000000000,1000000000000000000000000000,1000000000000000000000000000
Arg [8] : _selectors (bytes4[2]): System.Byte[],System.Byte[]
-----Encoded View---------------
51 Constructor Arguments found :
Arg [0] : 000000000000000000000000909583f64948e4c6a9c7a9285c292e9d9302fb96
Arg [1] : 0000000000000000000000005db7ad07d4903579a0342f7332bd4e3ed480d1af
Arg [2] : 0000000000000000000000005db7ad07d4903579a0342f7332bd4e3ed480d1af
Arg [3] : 0000000000000000000000002ff4e5ff77e49eba45bffea2f75814d114f9c904
Arg [4] : 00000000000000000000000051b206899bcfcbf4530412a43ed5c2336f91c90c
Arg [5] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [8] : 00000000000000000000000000000000000000000000000000000000000001e0
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000420
Arg [10] : 00000000000000000000000000000000000000000000000000000000000004e0
Arg [11] : 00000000000000000000000000000000000000000000000000000000000005a0
Arg [12] : 40c10f1900000000000000000000000000000000000000000000000000000000
Arg [13] : 42966c6800000000000000000000000000000000000000000000000000000000
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000011
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [17] : 000000000000000000000000000000000000000000000000000000000000a4b1
Arg [18] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [19] : 0000000000000000000000000000000000000000000000000000000000002105
Arg [20] : 000000000000000000000000000000000000000000000000000000000000e708
Arg [21] : 0000000000000000000000000000000000000000000000000000000000013e31
Arg [22] : 0000000000000000000000000000000000000000000000000000000000000089
Arg [23] : 0000000000000000000000000000000000000000000000000000000000000d0a
Arg [24] : 0000000000000000000000000000000000000000000000000000000000000082
Arg [25] : 00000000000000000000000000000000000000000000000000000000000138de
Arg [26] : 0000000000000000000000000000000000000000000000000000000000001388
Arg [27] : 0000000000000000000000000000000000000000000000000000000000000092
Arg [28] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [29] : 0000000000000000000000000000000000000000000000000000000000000038
Arg [30] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [31] : 00000000000000000000000000000000000000000000000000000000000000df
Arg [32] : 0000000000000000000000000000000000000000000000000000000000018232
Arg [33] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [34] : 000000000000000000000000cb8530f2b20f3c62602f01d3a78bcc58e9aea853
Arg [35] : 0000000000000000000000005ef37628d45c80740fb6db7ed9c0a753b4f85263
Arg [36] : 000000000000000000000000a9bd5559531fe372e866ad4337599962d5810e01
Arg [37] : 0000000000000000000000000ea1c09b884dc5758ed1d9bd006dceb20d31c439
Arg [38] : 000000000000000000000000dea0243b5ee5200d1feba615eaa7385598417b86
Arg [39] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [40] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Arg [41] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Arg [42] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Arg [43] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Arg [44] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Arg [45] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [46] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Arg [47] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Arg [48] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Arg [49] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Arg [50] : 0000000000000000000000000000000000000000033b2e3c9fd0803ce8000000
Net Worth in USD
Net Worth in ETH
Token Allocations
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ARB | 100.00% | $0.999625 | 16,589.9855 | $16,583.76 |
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.