Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
MultiLockMintERC721Pool
Compiler Version
v0.8.29+commit.ab55807c
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {TokenPool} from "src/pools/TokenPool.sol";
import {MultiTokenPool} from "src/pools/MultiTokenPool.sol";
import {LockMintERC721Pool} from "src/pools/erc721/LockMintERC721Pool.sol";
import {IMultiLockMintERC721Pool} from "src/interfaces/pools/erc721/IMultiLockMintERC721Pool.sol";
import {Pool} from "src/libraries/Pool.sol";
contract MultiLockMintERC721Pool is MultiTokenPool, LockMintERC721Pool, IMultiLockMintERC721Pool {
string public constant override typeAndVersion = "MultiLockMintERC721Pool 1.0.0";
constructor() {
_disableInitializers();
}
function initialize(address admin, address router, uint64 currentChainSelector) external initializer {
_grantRole(DEFAULT_ADMIN_ROLE, admin);
__PausableExtended_init(admin);
__RateLimitConsumer_init(admin);
__SharedStorageConsumer_init(admin);
__TokenPool_init(admin, router, currentChainSelector);
}
/**
* @inheritdoc IMultiLockMintERC721Pool
*/
function withdrawLiquidity(address[] calldata localTokens, address[] calldata tos, uint256[] calldata ids)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
uint256 tokenCount = localTokens.length;
_requireEqualLength(tokenCount, ids.length);
_requireEqualLength(tokenCount, tos.length);
_requireNonZero(tokenCount);
for (uint256 i; i < tokenCount; ++i) {
_requireLocalToken(localTokens[i]);
_requireNonZero(tos[i]);
IERC721(localTokens[i]).transferFrom(address(this), tos[i], ids[i]);
}
}
/**
* @inheritdoc IMultiLockMintERC721Pool
*/
function crossTransfer(
address localToken,
uint64 remoteChainSelector,
address to,
uint256 id,
address feeToken,
uint256 gasLimit
) external payable returns (bytes32 messageId) {
return _crossBatchTransfer(localToken, remoteChainSelector, to, _toSingletonArray(id), feeToken, gasLimit);
}
/**
* @inheritdoc IMultiLockMintERC721Pool
*/
function crossBatchTransfer(
address localToken,
uint64 remoteChainSelector,
address to,
uint256[] calldata ids,
address feeToken,
uint256 gasLimit
) external payable returns (bytes32 messageId) {
return _crossBatchTransfer(localToken, remoteChainSelector, to, ids, feeToken, gasLimit);
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(MultiTokenPool, LockMintERC721Pool)
returns (bool)
{
return interfaceId == type(IMultiLockMintERC721Pool).interfaceId
|| LockMintERC721Pool.supportsInterface(interfaceId) || MultiTokenPool.supportsInterface(interfaceId);
}
function _releaseOrMint(Pool.ReleaseOrMint memory releaseOrMint)
internal
virtual
override(TokenPool, LockMintERC721Pool)
{
// Prevent the case when localToken is mapped to many remote chains
// and the message is sent to from the remote chain that is unmapped with the localToken
_requireNonZero(getRemoteToken(releaseOrMint.localToken, releaseOrMint.remoteChainSelector));
super._releaseOrMint(releaseOrMint);
}
function _crossBatchTransfer(
address localToken,
uint64 remoteChainSelector,
address to,
uint256[] memory ids,
address feeToken,
uint256 gasLimit
) internal nonZero(to) returns (bytes32 messageId) {
bytes memory data = abi.encode(ids);
_lockOrBurn(
Pool.LockOrBurn({remoteChainSelector: remoteChainSelector, localToken: localToken, extraData: data})
);
address remoteToken = getRemoteToken(localToken, remoteChainSelector);
_requireNonZero(remoteToken);
messageId = _sendDataPayFeeToken({
remoteChainSelector: remoteChainSelector,
receiver: getRemotePool(remoteChainSelector),
data: abi.encode(
Pool.ReleaseOrMint({
originalSender: msg.sender,
remoteChainSelector: getCurrentChainSelector(),
receiver: to,
localToken: remoteToken,
remotePoolAddress: address(this),
remotePoolData: data
})
),
gasLimit: gasLimit,
allowOutOfOrderExecution: true,
feeToken: feeToken
});
_storeMessageId(getCurrentChainSelector(), messageId);
}
function _toSingletonArray(uint256 id) internal pure returns (uint256[] memory ids) {
ids = new uint256[](1);
ids[0] = id;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {ITypeAndVersion} from "@chainlink/contracts-ccip/src/v0.8/shared/interfaces/ITypeAndVersion.sol";
import {AccessControlEnumerableUpgradeable} from
"@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";
import {CCIPSenderReceiverUpgradeable} from "src/extensions/CCIPSenderReceiverUpgradeable.sol";
import {ITokenPool} from "src/interfaces/pools/ITokenPool.sol";
import {Pool} from "src/libraries/Pool.sol";
abstract contract TokenPool is AccessControlEnumerableUpgradeable, CCIPSenderReceiverUpgradeable, ITokenPool {
bytes32 public constant TOKEN_POOL_OWNER_ROLE = keccak256("TOKEN_POOL_OWNER_ROLE");
/// @dev Gap for future upgrades
uint256[50] private __gap1;
/// @dev Mapping of chain selector to array of message IDs
mapping(uint64 chainSelector => bytes32[] messageIds) private s_messageIds;
/// @dev Mapping of chain selector to exists mapping of message IDs
mapping(uint64 chainSelector => mapping(bytes32 messageId => bool exists)) private s_messageIdExists;
/// @dev Gap for future upgrades
uint256[50] private __gap2;
modifier onlyLocalToken(address localToken) {
_requireLocalToken(localToken);
_;
}
function __TokenPool_init(address owner, address router, uint64 currentChainSelector) internal onlyInitializing {
__TokenPool_init_unchained(owner);
__CCIPSenderReceiver_init(router, currentChainSelector);
}
function __TokenPool_init_unchained(address owner) internal onlyInitializing {
_grantRole(TOKEN_POOL_OWNER_ROLE, owner);
}
/**
* @inheritdoc ITokenPool
*/
function addRemotePool(uint64 remoteChainSelector, address remotePool) external onlyRole(TOKEN_POOL_OWNER_ROLE) {
_addRemoteChain(remoteChainSelector, remotePool);
emit RemotePoolAdded(msg.sender, remoteChainSelector, remotePool);
}
/**
* @inheritdoc ITokenPool
*/
function removeRemotePool(uint64 remoteChainSelector) external onlyRole(TOKEN_POOL_OWNER_ROLE) {
_removeRemoteChain(remoteChainSelector);
emit RemotePoolRemoved(msg.sender, remoteChainSelector);
}
/**
* @inheritdoc ITokenPool
*/
function mapRemoteToken(address localToken, uint64 remoteChainSelector, address remoteToken)
external
onlyRole(TOKEN_POOL_OWNER_ROLE)
nonZero(localToken)
onlyEnabledChain(remoteChainSelector)
{
_requireNonZero(remoteToken);
_mapRemoteToken(localToken, remoteChainSelector, remoteToken);
emit RemoteTokenMapped(msg.sender, remoteChainSelector, localToken, remoteToken);
}
/**
* @inheritdoc ITokenPool
*/
function unmapRemoteToken(address localToken, uint64 remoteChainSelector)
external
onlyRole(TOKEN_POOL_OWNER_ROLE)
onlyEnabledChain(remoteChainSelector)
{
_unmapRemoteToken(localToken, remoteChainSelector);
emit RemoteTokenUnmapped(msg.sender, remoteChainSelector, localToken);
}
/**
* @inheritdoc ITokenPool
*/
function getRemotePool(uint64 remoteChainSelector) public view returns (address remotePool) {
return _getRemoteSender(remoteChainSelector);
}
/**
* @inheritdoc ITokenPool
*/
function getRemotePools()
external
view
returns (uint64[] memory remoteChainSelectors, address[] memory remotePools)
{
remoteChainSelectors = getSupportedChains();
uint256 length = remoteChainSelectors.length;
remotePools = new address[](length);
for (uint256 i; i < length; ++i) {
remotePools[i] = getRemotePool(remoteChainSelectors[i]);
}
}
/**
* @inheritdoc ITokenPool
*/
function getMessageIds(uint64 chainSelector, uint256 offset, uint256 limit)
external
view
returns (uint256 length, bytes32[] memory messageIds)
{
length = s_messageIds[chainSelector].length;
if (offset >= length) return (length, new bytes32[](0));
if (offset + limit > length) limit = length - offset;
messageIds = new bytes32[](limit);
for (uint256 i; i < limit; ++i) {
messageIds[i] = s_messageIds[chainSelector][offset + i];
}
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(AccessControlEnumerableUpgradeable, CCIPSenderReceiverUpgradeable)
returns (bool)
{
return interfaceId == type(ITypeAndVersion).interfaceId || interfaceId == type(ITokenPool).interfaceId
|| super.supportsInterface(interfaceId);
}
function _storeMessageId(uint64 chainSelector, bytes32 messageId) internal {
if (s_messageIdExists[chainSelector][messageId]) revert MessageIdAlreadyExists(chainSelector, messageId);
s_messageIds[chainSelector].push(messageId);
s_messageIdExists[chainSelector][messageId] = true;
}
/**
* @dev Virtual function to be implemented by derived contracts to handle the lock or burn operation.
*/
function _lockOrBurn(Pool.LockOrBurn memory lockOrBurn) internal virtual;
/**
* @dev Virtual function to be implemented by derived contracts to handle the release or mint operation.
*/
function _releaseOrMint(Pool.ReleaseOrMint memory releaseOrMint) internal virtual;
/**
* @dev Virtual function to be implemented by derived contracts to handle the mapping of remote tokens.
*/
function _mapRemoteToken(address localToken, uint64 remoteChainSelector, address remoteToken) internal virtual;
/**
* @dev Virtual function to be implemented by derived contracts to handle the unmapping of remote tokens.
*/
function _unmapRemoteToken(address localToken, uint64 remoteChainSelector) internal virtual;
/**
* @dev Internal function to require that the local token is supported by the pool.
*/
function _requireLocalToken(address localToken) internal view virtual;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {TokenPool} from "src/pools/TokenPool.sol";
import {ITokenPool} from "src/interfaces/pools/ITokenPool.sol";
import {IMultiTokenPool} from "src/interfaces/pools/IMultiTokenPool.sol";
abstract contract MultiTokenPool is TokenPool, IMultiTokenPool {
using EnumerableSet for EnumerableSet.AddressSet;
/// @dev Gap for future upgrades
uint256[50] private __gap1;
/// @dev The set of local tokens.
EnumerableSet.AddressSet private s_localTokens;
/// @dev The mapping of local token address => remote chain selector => remote token address.
mapping(address local => mapping(uint64 remoteChainSelector => address)) private s_remoteTokens;
/// @dev Gap for future upgrades
uint256[50] private __gap2;
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IMultiTokenPool).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IMultiTokenPool
*/
function getSupportedTokensForChain(uint64 remoteChainSelector)
public
view
returns (address[] memory localTokens, address[] memory remoteTokens)
{
if (!isSupportedChain(remoteChainSelector)) return (new address[](0), new address[](0));
uint256 tokenCount = s_localTokens.length();
localTokens = new address[](tokenCount);
remoteTokens = new address[](tokenCount);
uint256 count;
for (uint256 i; i < tokenCount; ++i) {
address localToken = s_localTokens.at(i);
address remoteToken = s_remoteTokens[localToken][remoteChainSelector];
if (remoteToken != address(0)) {
localTokens[count] = localToken;
remoteTokens[count] = remoteToken;
++count;
}
}
assembly ("memory-safe") {
mstore(localTokens, count)
mstore(remoteTokens, count)
}
}
/**
* @inheritdoc IMultiTokenPool
*/
function getTokens() public view returns (address[] memory localTokens) {
address[] memory tokenSet = s_localTokens.values();
uint256 tokenCount = tokenSet.length;
localTokens = new address[](tokenCount);
uint256 count;
for (uint256 i; i < tokenCount; ++i) {
if (isSupportedToken(tokenSet[i])) {
localTokens[count++] = tokenSet[i];
}
}
assembly ("memory-safe") {
mstore(localTokens, count)
}
}
/**
* @inheritdoc ITokenPool
*/
function isSupportedToken(address localToken) public view virtual override returns (bool yes) {
// Short circuit if the token is not in the set
if (!s_localTokens.contains(localToken)) return false;
// Check if the token has a mapping on any enabled chain
uint64[] memory supportedChains = getSupportedChains();
uint256 chainCount = supportedChains.length;
for (uint256 i; i < chainCount; ++i) {
if (getRemoteToken(localToken, supportedChains[i]) != address(0)) {
return true;
}
}
return false;
}
/**
* @inheritdoc IMultiTokenPool
*/
function getRemoteToken(address localToken, uint64 remoteChainSelector) public view returns (address remoteToken) {
if (!isSupportedChain(remoteChainSelector)) return address(0);
return s_remoteTokens[localToken][remoteChainSelector];
}
/**
* @dev See {ITokenPool-mapRemoteToken}.
*/
function _mapRemoteToken(address localToken, uint64 remoteChainSelector, address remoteToken)
internal
virtual
override
{
// Check if the remote token is already mapped to the local token
(address[] memory existingLocalTokens, address[] memory existingRemoteTokens) =
getSupportedTokensForChain(remoteChainSelector);
if (existingRemoteTokens.length > 0) {
for (uint256 i; i < existingRemoteTokens.length; ++i) {
if (existingRemoteTokens[i] == remoteToken) {
revert TokenAlreadyMapped(existingLocalTokens[i], remoteToken);
}
}
}
s_localTokens.add(localToken);
s_remoteTokens[localToken][remoteChainSelector] = remoteToken;
}
/**
* @dev See {ITokenPool-unmapRemoteToken}.
*/
function _unmapRemoteToken(address localToken, uint64 remoteChainSelector) internal virtual override {
address remoteToken = s_remoteTokens[localToken][remoteChainSelector];
if (remoteToken == address(0)) revert TokenNotMapped(localToken, remoteChainSelector);
delete s_remoteTokens[localToken][remoteChainSelector];
// If the token is not mapped to any other chain, remove it from the set
if (!isSupportedToken(localToken)) s_localTokens.remove(localToken);
}
/**
* @dev See {TokenPool-requireLocalToken}.
*/
function _requireLocalToken(address localToken) internal view virtual override {
if (!isSupportedToken(localToken)) revert OnlyLocalToken();
}
/**
* @dev Checks if the two arrays have the same length.
*/
function _requireEqualLength(uint256 a, uint256 b) internal pure {
if (a != b) revert LengthMismatch(a, b);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {AccessControlEnumerableUpgradeable} from
"@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC721Mintable} from "src/interfaces/external/IERC721Mintable.sol";
import {PausableExtendedUpgradeable} from "src/extensions/PausableExtendedUpgradeable.sol";
import {RateLimitConsumerUpgradeable} from "src/extensions/RateLimitConsumerUpgradeable.sol";
import {SharedStorageConsumerUpgradeable} from "src/extensions/SharedStorageConsumerUpgradeable.sol";
import {TokenPool} from "src/pools/TokenPool.sol";
import {ILockMintERC721Pool} from "src/interfaces/pools/erc721/ILockMintERC721Pool.sol";
import {Pool} from "src/libraries/Pool.sol";
abstract contract LockMintERC721Pool is
PausableExtendedUpgradeable,
RateLimitConsumerUpgradeable,
SharedStorageConsumerUpgradeable,
TokenPool,
ILockMintERC721Pool
{
/**
* @inheritdoc ILockMintERC721Pool
*/
function estimateFee(address feeToken, uint64 remoteChainSelector, uint256 tokenCount, uint256 gasLimit)
external
view
returns (uint256 fee)
{
Pool.ReleaseOrMint memory empty;
empty.remotePoolData = abi.encode(new uint256[](tokenCount));
(fee,) = _getSendDataFee({
remoteChainSelector: remoteChainSelector,
receiver: getRemotePool(remoteChainSelector),
data: abi.encode(empty),
gasLimit: gasLimit,
allowOutOfOrderExecution: true,
feeToken: feeToken
});
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(PausableExtendedUpgradeable, RateLimitConsumerUpgradeable, SharedStorageConsumerUpgradeable, TokenPool)
returns (bool)
{
return interfaceId == type(ILockMintERC721Pool).interfaceId || TokenPool.supportsInterface(interfaceId)
|| SharedStorageConsumerUpgradeable.supportsInterface(interfaceId)
|| RateLimitConsumerUpgradeable.supportsInterface(interfaceId)
|| PausableExtendedUpgradeable.supportsInterface(interfaceId);
}
function _ccipReceive(Client.Any2EVMMessage calldata message) internal virtual override {
Pool.ReleaseOrMint memory releaseOrMint = abi.decode(message.data, (Pool.ReleaseOrMint));
// Validate the message.sourceChainSelector against the releaseOrMint.remoteChainSelector
if (message.sourceChainSelector != releaseOrMint.remoteChainSelector) {
revert RemoteChainSelectorNotMatch(message.sourceChainSelector, releaseOrMint.remoteChainSelector);
}
// Validate the message.sender against the releaseOrMint.remotePoolAddress
address remoteSender = abi.decode(message.sender, (address));
if (remoteSender != releaseOrMint.remotePoolAddress) {
revert RemotePoolNotMatch(remoteSender, releaseOrMint.remotePoolAddress);
}
_requireNonZero(releaseOrMint.originalSender);
_storeMessageId(releaseOrMint.remoteChainSelector, message.messageId);
_releaseOrMint(releaseOrMint);
emit CrossTransfer(
releaseOrMint.originalSender,
releaseOrMint.receiver,
message.messageId,
abi.decode(releaseOrMint.remotePoolData, (uint256[])),
message.sourceChainSelector,
getCurrentChainSelector()
);
}
function _releaseOrMint(Pool.ReleaseOrMint memory releaseOrMint) internal virtual override whenNotPaused {
uint256[] memory ids = abi.decode(releaseOrMint.remotePoolData, (uint256[]));
uint256 tokenCount = ids.length;
_requireNonZero(tokenCount);
_requireNonZero(releaseOrMint.receiver);
_requireLocalToken(releaseOrMint.localToken);
for (uint256 i; i < tokenCount; ++i) {
uint256 id = ids[i];
address owned = _tryGetOwnerOf(releaseOrMint.localToken, id);
if (owned == address(this) || isSharedStorage(owned)) {
IERC721(releaseOrMint.localToken).transferFrom(owned, releaseOrMint.receiver, id);
} else {
IERC721Mintable(releaseOrMint.localToken).mint(releaseOrMint.receiver, id);
}
}
_requireDelivered(releaseOrMint.localToken, releaseOrMint.receiver, ids);
_consumeInboundRateLimit(releaseOrMint.remoteChainSelector, releaseOrMint.localToken, tokenCount);
}
function _lockOrBurn(Pool.LockOrBurn memory lockOrBurn)
internal
virtual
override
whenNotPaused
onlyLocalToken(lockOrBurn.localToken)
onlyEnabledChain(lockOrBurn.remoteChainSelector)
{
uint256[] memory ids = abi.decode(lockOrBurn.extraData, (uint256[]));
uint256 tokenCount = ids.length;
_requireNonZero(tokenCount);
for (uint256 i; i < tokenCount; ++i) {
IERC721(lockOrBurn.localToken).transferFrom(msg.sender, address(this), ids[i]);
}
_requireDelivered(lockOrBurn.localToken, address(this), ids);
_consumeOutboundRateLimit(lockOrBurn.remoteChainSelector, lockOrBurn.localToken, tokenCount);
}
function _requireDelivered(address token, address recipient, uint256[] memory ids) internal view {
uint256 tokenCount = ids.length;
for (uint256 i; i < tokenCount; ++i) {
if (_tryGetOwnerOf(token, ids[i]) != recipient) revert ERC721TransferFailed(recipient, ids[i]);
}
}
function _tryGetOwnerOf(address token, uint256 id) internal view returns (address ownedBy) {
try IERC721(token).ownerOf(id) returns (address by) {
return by;
} catch {
// Handle the case where the token does not exist or is not an ERC721
return address(0);
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface IMultiLockMintERC721Pool {
/**
* @dev Withdraw the liquidity of the tokens in the pool.
* Requirements:
* - The caller must have `DEFAULT_ADMIN_ROLE`.
* - The `localTokens` must be the same length as `tos` and `ids`.
* - The `tos` must not be zero.
* - `localTokens` must be supported by the pool.
*/
function withdrawLiquidity(address[] calldata localTokens, address[] calldata tos, uint256[] calldata ids)
external;
/**
* @dev Cross transfer a single token to the remote chain.
* Requirements:
* - `to` must not be zero.
* - `id` must be approved for transfer.
* - token fee should be query via `estimateFee` before calling this function.
* - if `feeToken` is native (address(0)), the caller must send enough native tokens to cover the fee.
* - if `feeToken` is ERC20, the caller must approve the pool to spend the fee token.
* @return messageId The message ID of the cross transfer.
*/
function crossTransfer(
address localToken,
uint64 remoteChainSelector,
address to,
uint256 id,
address feeToken,
uint256 gasLimit
) external payable returns (bytes32 messageId);
/**
* @dev Cross transfer multiple tokens to the remote chain.
* Requirements:
* - `to` must not be zero.
* - `ids` must be approved for transfer.
* - token fee should be query via `estimateFee` before calling this function.
* - if `feeToken` is native (address(0)), the caller must send enough native tokens to cover the fee.
* - if `feeToken` is ERC20, the caller must approve the pool to spend the fee token.
* @return messageId The message ID of the cross transfer.
*/
function crossBatchTransfer(
address localToken,
uint64 remoteChainSelector,
address to,
uint256[] calldata ids,
address feeToken,
uint256 gasLimit
) external payable returns (bytes32 messageId);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
library Pool {
struct LockOrBurn {
uint64 remoteChainSelector;
address localToken;
bytes extraData;
}
struct ReleaseOrMint {
address originalSender;
uint64 remoteChainSelector;
address receiver;
address localToken;
address remotePoolAddress;
bytes remotePoolData;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @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
pragma solidity ^0.8.0;
interface ITypeAndVersion {
function typeAndVersion() external pure returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/extensions/AccessControlEnumerable.sol)
pragma solidity ^0.8.20;
import {IAccessControlEnumerable} from "@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol";
import {AccessControlUpgradeable} from "../AccessControlUpgradeable.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerable, AccessControlUpgradeable {
using EnumerableSet for EnumerableSet.AddressSet;
/// @custom:storage-location erc7201:openzeppelin.storage.AccessControlEnumerable
struct AccessControlEnumerableStorage {
mapping(bytes32 role => EnumerableSet.AddressSet) _roleMembers;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControlEnumerable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessControlEnumerableStorageLocation = 0xc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e82371705932000;
function _getAccessControlEnumerableStorage() private pure returns (AccessControlEnumerableStorage storage $) {
assembly {
$.slot := AccessControlEnumerableStorageLocation
}
}
function __AccessControlEnumerable_init() internal onlyInitializing {
}
function __AccessControlEnumerable_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {
AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
return $._roleMembers[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {
AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
return $._roleMembers[role].length();
}
/**
* @dev Return all accounts that have `role`
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function getRoleMembers(bytes32 role) public view virtual returns (address[] memory) {
AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
return $._roleMembers[role].values();
}
/**
* @dev Overload {AccessControl-_grantRole} to track enumerable memberships
*/
function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {
AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
bool granted = super._grantRole(role, account);
if (granted) {
$._roleMembers[role].add(account);
}
return granted;
}
/**
* @dev Overload {AccessControl-_revokeRole} to track enumerable memberships
*/
function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {
AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
bool revoked = super._revokeRole(role, account);
if (revoked) {
$._roleMembers[role].remove(account);
}
return revoked;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {IRMN} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRMN.sol";
import {IWrappedNative} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IWrappedNative.sol";
import {IAny2EVMMessageReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IAny2EVMMessageReceiver.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {IRouterClientExtended} from "src/interfaces/external/IRouterClientExtended.sol";
import {IEVM2EVMOnRamp} from "src/interfaces/external/IEVM2EVMOnRamp.sol";
import {ICCIPSenderReceiver} from "src/interfaces/extensions/ICCIPSenderReceiver.sol";
import {Error} from "src/libraries/Error.sol";
abstract contract CCIPSenderReceiverUpgradeable is Initializable, ICCIPSenderReceiver {
using SafeERC20 for IERC20;
using EnumerableSet for EnumerableSet.UintSet;
/// @dev Gap for future storage
uint256[50] private __gap1;
/// @dev Current chain selector
uint64 private s_currentChainSelector;
/// @dev CCIP Risk Management Network Proxy
IRMN private s_rmnProxy;
/// @dev CCIP Router
IRouterClientExtended private s_router;
/// @dev Remote chain selectors set
EnumerableSet.UintSet private s_remoteChainSelectors;
/// @dev Mapping of remote chain selector to enabled sender. This is the address that is allowed to send messages from the remote chain.
mapping(uint64 remoteChainSelector => address) private s_remoteSenders;
/// @dev Gap for future storage
uint256[50] private __gap2;
modifier onlyEnabledChain(uint64 remoteChainSelector) {
_requireEnabledChain(remoteChainSelector);
_;
}
modifier onlyLocalChain(uint64 currentChainSelector) {
_requireLocalChain(currentChainSelector);
_;
}
modifier nonZero(address addr) {
_requireNonZero(addr);
_;
}
modifier notCursed(uint64 remoteChainSelector) {
_requireNotCursed(remoteChainSelector);
_;
}
function __CCIPSenderReceiver_init(address router, uint64 currentChainSelector) internal onlyInitializing {
__CCIPSenderReceiver_init_unchained(router, currentChainSelector);
}
function __CCIPSenderReceiver_init_unchained(address router, uint64 currentChainSelector)
internal
onlyInitializing
{
_requireNonZero(currentChainSelector);
s_router = IRouterClientExtended(router);
s_rmnProxy = IRMN(s_router.getArmProxy());
s_currentChainSelector = currentChainSelector;
}
/**
* @inheritdoc IAny2EVMMessageReceiver
*/
function ccipReceive(Client.Any2EVMMessage calldata message)
external
override
notCursed(message.sourceChainSelector)
{
address sender = abi.decode(message.sender, (address));
_requireEnabledSender(message.sourceChainSelector, sender);
_requireRouter();
_ccipReceive(message);
emit MessageReceived(sender, message.messageId);
}
/**
* @inheritdoc ICCIPSenderReceiver
*/
function isFeeTokenSupported(uint64 remoteChainSelector, address feeToken) external view returns (bool yes) {
address[] memory feeTokens = getFeeTokens(remoteChainSelector);
uint256 feeTokenCount = feeTokens.length;
if (feeTokenCount == 0) return false;
for (uint256 i; i < feeTokenCount; ++i) {
if (feeTokens[i] == feeToken) return true;
}
return false;
}
/**
* @inheritdoc ICCIPSenderReceiver
*/
function getFeeTokens(uint64 remoteChainSelector)
public
view
onlyEnabledChain(remoteChainSelector)
returns (address[] memory feeTokens)
{
return IEVM2EVMOnRamp(s_router.getOnRamp(remoteChainSelector)).getDynamicConfig().priceRegistry.getFeeTokens();
}
/**
* @inheritdoc ICCIPSenderReceiver
*/
function isLocalChain(uint64 currentChainSelector) public view returns (bool yes) {
return currentChainSelector == s_currentChainSelector;
}
/**
* @inheritdoc ICCIPSenderReceiver
*/
function isSupportedChain(uint64 remoteChainSelector) public view returns (bool yes) {
return s_remoteChainSelectors.contains(remoteChainSelector) && s_router.isChainSupported(remoteChainSelector);
}
/**
* @inheritdoc ICCIPSenderReceiver
*/
function isSenderEnabled(uint64 remoteChainSelector, address sender) public view returns (bool yes) {
if (!isSupportedChain(remoteChainSelector)) return false;
return s_remoteSenders[remoteChainSelector] == sender;
}
/**
* @inheritdoc ICCIPSenderReceiver
*/
function getSupportedChains() public view returns (uint64[] memory remoteChainSelectors) {
uint256[] memory values = s_remoteChainSelectors.values();
uint256 length = values.length;
remoteChainSelectors = new uint64[](length);
uint256 count;
for (uint256 i; i < length; ++i) {
uint64 chain = uint64(values[i]);
if (s_router.isChainSupported(chain)) {
remoteChainSelectors[count++] = chain;
}
}
assembly ("memory-safe") {
// Resize the array to the actual number of supported chains
mstore(remoteChainSelectors, count)
}
}
/**
* @inheritdoc ICCIPSenderReceiver
*/
function getCurrentChainSelector() public view returns (uint64 currentChainSelector) {
return s_currentChainSelector;
}
/**
* @inheritdoc ICCIPSenderReceiver
*/
function getRouter() public view returns (IRouterClientExtended router) {
return s_router;
}
/**
* @inheritdoc ICCIPSenderReceiver
*/
function getRmnProxy() external view returns (IRMN rmnProxy) {
return s_rmnProxy;
}
/**
* @notice IERC165 supports an interfaceId
* @param interfaceId The interfaceId to check
* @return true if the interfaceId is supported
* @dev Should indicate whether the contract implements IAny2EVMMessageReceiver
* e.g. return interfaceId == type(IAny2EVMMessageReceiver).interfaceId || interfaceId == type(IERC165).interfaceId
* This allows CCIP to check if ccipReceive is available before calling it.
* If this returns false or reverts, only tokens are transferred to the receiver.
* If this returns true, tokens are transferred and ccipReceive is called atomically.
* Additionally, if the receiver address does not have code associated with
* it at the time of execution (EXTCODESIZE returns 0), only tokens will be transferred.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(ICCIPSenderReceiver).interfaceId
|| interfaceId == type(IAny2EVMMessageReceiver).interfaceId || interfaceId == type(IERC165).interfaceId;
}
/**
* @notice Override this function in your implementation.
* @param message Any2EVMMessage
*/
function _ccipReceive(Client.Any2EVMMessage calldata message) internal virtual;
/**
* @dev Enable a remote chain
* @param remoteChainSelector The chain selector of the remote chain
* @param remoteSender The address of the sender on the remote chain
*/
function _addRemoteChain(uint64 remoteChainSelector, address remoteSender) internal {
_requireNonZero(remoteSender);
if (remoteChainSelector == s_currentChainSelector) revert OnlyRemoteChain(remoteChainSelector);
if (!s_router.isChainSupported(remoteChainSelector)) revert ChainNotSupported(remoteChainSelector);
if (!s_remoteChainSelectors.add(remoteChainSelector)) revert ChainAlreadyEnabled(remoteChainSelector);
s_remoteSenders[remoteChainSelector] = remoteSender;
emit RemoteChainEnabled(msg.sender, remoteChainSelector, remoteSender);
}
/**
* @dev Disable a remote chain
* @param remoteChainSelector The chain selector of the remote chain
*/
function _removeRemoteChain(uint64 remoteChainSelector) internal {
if (!s_remoteChainSelectors.remove(remoteChainSelector)) revert NonExistentChain(remoteChainSelector);
delete s_remoteSenders[remoteChainSelector];
emit RemoteChainDisabled(msg.sender, remoteChainSelector);
}
/**
* @notice Send data to a remote chain and pay fee by ERC20 token
* If the feeToken is address(0), the fee will be wrapped into WrappedNative token.
* Revert if the feeToken is not supported by the remote chain.
*/
function _sendDataPayFeeToken(
uint64 remoteChainSelector,
address receiver,
bytes memory data,
uint256 gasLimit,
bool allowOutOfOrderExecution,
address feeToken
) internal notCursed(remoteChainSelector) returns (bytes32 messageId) {
_requireNonZero(receiver);
_requireNonZero(gasLimit);
_requireNonZero(data.length);
(uint256 fee, Client.EVM2AnyMessage memory message) =
_getSendDataFee(remoteChainSelector, receiver, data, gasLimit, allowOutOfOrderExecution, feeToken);
uint256 overspent;
if (feeToken == address(0)) {
if (msg.value < fee) revert InsufficientAllowance(fee, msg.value);
feeToken = s_router.getWrappedNative();
// Overwrite feeToken to wrapped native token
message.feeToken = feeToken;
IWrappedNative(feeToken).deposit{value: fee}();
overspent = msg.value - fee;
} else {
if (msg.value != 0) revert MsgValueNotAllowed(msg.value);
IERC20(feeToken).safeTransferFrom(msg.sender, address(this), fee);
}
IERC20(feeToken).approve(address(s_router), fee);
messageId = s_router.ccipSend(remoteChainSelector, message);
if (overspent > 0) {
// solhint-disable-next-line avoid-low-level-calls
(bool success,) = msg.sender.call{value: overspent}("");
if (!success) revert RefundFailed(msg.sender, overspent);
emit Refunded(msg.sender, overspent);
}
emit MessageSent(msg.sender, messageId);
}
/**
* @notice Estimate the fee for sending data to a remote chain
*/
function _getSendDataFee(
uint64 remoteChainSelector,
address receiver,
bytes memory data,
uint256 gasLimit,
bool allowOutOfOrderExecution,
address feeToken
) internal view onlyEnabledChain(remoteChainSelector) returns (uint256 fee, Client.EVM2AnyMessage memory message) {
message = Client.EVM2AnyMessage({
receiver: abi.encode(receiver),
data: data,
tokenAmounts: new Client.EVMTokenAmount[](0),
extraArgs: Client._argsToBytes(
Client.EVMExtraArgsV2({gasLimit: gasLimit, allowOutOfOrderExecution: allowOutOfOrderExecution})
),
feeToken: feeToken
});
fee = s_router.getFee(remoteChainSelector, message);
}
function _getRemoteSender(uint64 remoteChainSelector) internal view returns (address remoteAddress) {
if (!isSupportedChain(remoteChainSelector)) return address(0);
return s_remoteSenders[remoteChainSelector];
}
function _requireLocalChain(uint64 currentChainSelector) internal view {
if (currentChainSelector != s_currentChainSelector) revert OnlyLocalChain(currentChainSelector);
}
function _requireRouter() internal view {
if (msg.sender != address(s_router)) revert InvalidRouter(address(s_router), msg.sender);
}
function _requireNonZero(address addr) internal pure {
if (addr == address(0)) revert Error.ZeroAddressNotAllowed();
}
function _requireNonZero(uint256 val) internal pure {
if (val == 0) revert ZeroValueNotAllowed();
}
function _requireNotCursed(uint64 remoteChainSelector) internal view {
if (s_rmnProxy.isCursed(bytes16(uint128(remoteChainSelector)))) revert CursedByRMN();
}
function _requireEnabledChain(uint64 remoteChainSelector) internal view {
if (!isSupportedChain(remoteChainSelector)) revert NonExistentChain(remoteChainSelector);
}
function _requireEnabledSender(uint64 remoteChainSelector, address sender) internal view {
if (!isSenderEnabled(remoteChainSelector, sender)) revert SenderNotEnabled(remoteChainSelector, sender);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {ITypeAndVersion} from "@chainlink/contracts-ccip/src/v0.8/shared/interfaces/ITypeAndVersion.sol";
interface ITokenPool is ITypeAndVersion {
/// @dev Throw if the messageId already exists.
error MessageIdAlreadyExists(uint64 chainSelector, bytes32 messageId);
/// @dev emit when gas config for cross-chain message is set.
event GasLimitConfigured(address indexed by, uint32 fixedGas, uint32 dynamicGas);
/// @dev emit when remote pool is added.
event RemotePoolAdded(address indexed by, uint64 indexed remoteChainSelector, address indexed remotePool);
/// @dev emit when remote pool is removed.
event RemotePoolRemoved(address indexed by, uint64 indexed remoteChainSelector);
/// @dev emit when remote token is mapped.
event RemoteTokenMapped(
address indexed by, uint64 indexed remoteChainSelector, address indexed localToken, address remoteToken
);
/// @dev emit when remote token is unmapped.
event RemoteTokenUnmapped(address indexed by, uint64 indexed remoteChainSelector, address indexed localToken);
/**
* @dev Token pool owner role.
* Value is equal to keccak256("TOKEN_POOL_OWNER_ROLE").
*/
function TOKEN_POOL_OWNER_ROLE() external view returns (bytes32);
/**
* @dev Enabled `remotePool` to interact with this pool.
* Requirements:
* - `remotePool` is not null.
* - `remoteChainSelector` is not null.
* - `remoteChainSelector` != `currentChainSelector`.
* - Caller must have `TOKEN_POOL_OWNER_ROLE`.
* - `remoteChainSelector` must be supported by CCIP router.
*/
function addRemotePool(uint64 remoteChainSelector, address remotePool) external;
/**
* @dev Disable `remotePool` to interact with this pool.
* Requirements:
* - `remoteChainSelector` is not null.
* - `remoteChainSelector` != `currentChainSelector`.
* - Caller must have `TOKEN_POOL_OWNER_ROLE`.
* - Remote pool must be added before.
*
* Removing a remote pool does not delete the token mappings for the specified remote chain.
* However, all tokens mapped to the removed remote pool will be deactivated.
*/
function removeRemotePool(uint64 remoteChainSelector) external;
/**
* @dev Map local token to remote token for a given remote chain.
* Requirements:
* - `localToken` is not null.
* - `remoteChainSelector` must be enabled.
* - `remoteToken` is not null.
* - Caller must have `TOKEN_POOL_OWNER_ROLE`.
*/
function mapRemoteToken(address localToken, uint64 remoteChainSelector, address remoteToken) external;
/**
* @dev Unmap local token to remote token for a given remote chain.
* Requirements:
* - `localToken` must be added before.
* - `remoteChainSelector` must be enabled.
* - Caller must have `TOKEN_POOL_OWNER_ROLE`.
* - If `remoteChainSelector` is not enabled in this pool or no remote token is mapped to `localToken`, `localToken` will be removed from the set.
*/
function unmapRemoteToken(address localToken, uint64 remoteChainSelector) external;
/**
* @dev Get all supported chain selectors along with their remote pools pair for this pool/
* @return remoteChainSelectors The list of remote chain selectors.
* @return remotePools The list of enabled sender pools for the given remote chain.
*/
function getRemotePools()
external
view
returns (uint64[] memory remoteChainSelectors, address[] memory remotePools);
/**
* @dev Get remote token address for a given local token and remote chain.
* Returns zero address if the token is not mapped or `remoteChainSelector` is disabled.
*/
function getRemotePool(uint64 remoteChainSelector) external view returns (address remotePool);
/**
* @dev Returns whether the token is supported by the pool.
*/
function isSupportedToken(address token) external view returns (bool yes);
/**
* @dev Returns the array of message IDs for the given chain selector.
*/
function getMessageIds(uint64 chainSelector, uint256 offset, uint256 limit)
external
view
returns (uint256 length, bytes32[] memory messageIds);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface IMultiTokenPool {
/// @dev Revert if the given token is not supported by the pool.
error OnlyLocalToken();
/// @dev Revert if array lengths do not match.
error LengthMismatch(uint256 expected, uint256 actual);
/// @dev Revert if the local token does not have remote token mapped given the remote chain.
error TokenNotMapped(address localToken, uint64 remoteChainSelector);
/// @dev Revert if the local token already has remote token mapped given the remote chain.
error TokenAlreadyMapped(address localToken, address remoteToken);
/**
* @dev Get all supported token pair for a given chain.
* Requirements:
* - The remote chain is be enabled by the pool.
* @param remoteChainSelector The selector of the remote chain.
* @return localTokens The list of local tokens supported by the pool.
* @return remoteTokens The list of remote tokens supported by the pool.
*/
function getSupportedTokensForChain(uint64 remoteChainSelector)
external
view
returns (address[] memory localTokens, address[] memory remoteTokens);
/**
* @dev Get all supported local tokens.
* @return localTokens The list of local tokens supported by the pool.
*/
function getTokens() external view returns (address[] memory localTokens);
/**
* @dev Get remote token address for a given local token and remote chain.
* Requirements:
* - The local token must be supported by the pool.
* - The remote chain must be enabled by the pool.
*/
function getRemoteToken(address localToken, uint64 remoteChainSelector)
external
view
returns (address remoteToken);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// End consumer library.
library Client {
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct EVMTokenAmount {
address token; // token address on the local chain.
uint256 amount; // Amount of tokens.
}
struct Any2EVMMessage {
bytes32 messageId; // MessageId corresponding to ccipSend on source.
uint64 sourceChainSelector; // Source chain selector.
bytes sender; // abi.decode(sender) if coming from an EVM chain.
bytes data; // payload sent in original message.
EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation.
}
// If extraArgs is empty bytes, the default is 200k gas limit.
struct EVM2AnyMessage {
bytes receiver; // abi.encode(receiver address) for dest EVM chains
bytes data; // Data payload
EVMTokenAmount[] tokenAmounts; // Token transfers
address feeToken; // Address of feeToken. address(0) means you will send msg.value.
bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV2)
}
// bytes4(keccak256("CCIP EVMExtraArgsV1"));
bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;
struct EVMExtraArgsV1 {
uint256 gasLimit;
}
function _argsToBytes(
EVMExtraArgsV1 memory extraArgs
) internal pure returns (bytes memory bts) {
return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);
}
// bytes4(keccak256("CCIP EVMExtraArgsV2"));
bytes4 public constant EVM_EXTRA_ARGS_V2_TAG = 0x181dcf10;
/// @param gasLimit: gas limit for the callback on the destination chain.
/// @param allowOutOfOrderExecution: if true, it indicates that the message can be executed in any order relative to other messages from the same sender.
/// This value's default varies by chain. On some chains, a particular value is enforced, meaning if the expected value
/// is not set, the message request will revert.
struct EVMExtraArgsV2 {
uint256 gasLimit;
bool allowOutOfOrderExecution;
}
function _argsToBytes(
EVMExtraArgsV2 memory extraArgs
) internal pure returns (bytes memory bts) {
return abi.encodeWithSelector(EVM_EXTRA_ARGS_V2_TAG, extraArgs);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
interface IERC721Mintable is IERC721 {
function mint(address to, uint256 id) external;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import {AccessControlEnumerableUpgradeable} from
"@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";
import {IPausable} from "src/interfaces/external/IPausable.sol";
import {IPausableExtended} from "src/interfaces/extensions/IPausableExtended.sol";
abstract contract PausableExtendedUpgradeable is
PausableUpgradeable,
AccessControlEnumerableUpgradeable,
IPausableExtended
{
/// @inheritdoc IPausableExtended
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
/// @dev Gap for future storage
uint256[50] private __gap1;
address private s_globalPauser;
/// @dev Gap for future storage
uint256[50] private __gap2;
function __PausableExtended_init(address globalPauser) internal onlyInitializing {
__PausableExtended_init_unchained(globalPauser);
}
function __PausableExtended_init_unchained(address globalPauser) internal onlyInitializing {
s_globalPauser = globalPauser;
_grantRole(PAUSER_ROLE, globalPauser);
}
/**
* @inheritdoc IPausableExtended
*/
function pause() external onlyRole(PAUSER_ROLE) {
_pause();
}
/**
* @inheritdoc IPausableExtended
*/
function unpause() external onlyRole(PAUSER_ROLE) {
_unpause();
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IPausableExtended).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IPausableExtended
*/
function getGlobalPauser() external view returns (address globalPauser) {
return s_globalPauser;
}
/**
* @inheritdoc IPausableExtended
*/
function setGlobalPauser(address globalPauser) external onlyRole(DEFAULT_ADMIN_ROLE) {
s_globalPauser = globalPauser;
if (globalPauser == address(0)) {
_revokeRole(PAUSER_ROLE, s_globalPauser);
return;
}
_grantRole(PAUSER_ROLE, globalPauser);
}
function paused() public view virtual override returns (bool) {
address globalPauser = s_globalPauser;
return (hasRole(PAUSER_ROLE, globalPauser) && _hasCode(globalPauser) && IPausable(globalPauser).paused())
|| PausableUpgradeable.paused();
}
function _hasCode(address target) private view returns (bool) {
return target.code.length > 0;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {RateLimiter} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/RateLimiter.sol";
import {AccessControlEnumerableUpgradeable} from
"@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";
import {IRateLimitConsumer} from "src/interfaces/extensions/IRateLimitConsumer.sol";
abstract contract RateLimitConsumerUpgradeable is AccessControlEnumerableUpgradeable, IRateLimitConsumer {
using RateLimiter for RateLimiter.Config;
using RateLimiter for RateLimiter.TokenBucket;
bytes32 public constant RATE_LIMITER_ROLE = keccak256("RATE_LIMITER_ROLE");
uint256[50] private __gap1;
/// @dev The outbound rate limit configuration for the given chain selector.
mapping(uint64 remoteChainSelector => RateLimiter.TokenBucket) private s_outboundConfig;
/// @dev The inbound rate limit configuration for the given chain selector.
mapping(uint64 remoteChainSelector => RateLimiter.TokenBucket) private s_inboundConfig;
uint256[50] private __gap2;
function __RateLimitConsumer_init(address rateLimiter) internal onlyInitializing {
__RateLimitConsumer_init_unchained(rateLimiter);
}
function __RateLimitConsumer_init_unchained(address rateLimiter) internal onlyInitializing {
_grantRole(RATE_LIMITER_ROLE, rateLimiter);
}
/**
* @inheritdoc IRateLimitConsumer
*/
function setChainRateLimiterConfig(
uint64 remoteChainSelector,
RateLimiter.Config calldata outboundConfig,
RateLimiter.Config calldata inboundConfig
) external onlyRole(RATE_LIMITER_ROLE) {
_setRateLimitConfig(remoteChainSelector, outboundConfig, inboundConfig);
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IRateLimitConsumer).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IRateLimitConsumer
*/
function getCurrentOutboundRateLimiterState(uint64 remoteChainSelector)
external
view
returns (RateLimiter.TokenBucket memory state)
{
return s_outboundConfig[remoteChainSelector]._currentTokenBucketState();
}
/**
* @inheritdoc IRateLimitConsumer
*/
function getCurrentInboundRateLimiterState(uint64 remoteChainSelector)
external
view
returns (RateLimiter.TokenBucket memory state)
{
return s_inboundConfig[remoteChainSelector]._currentTokenBucketState();
}
/**
* @notice Consumes outbound rate limiting capacity in this pool
*/
function _consumeOutboundRateLimit(uint64 remoteChainSelector, address token, uint256 amount) internal {
s_outboundConfig[remoteChainSelector]._consume(amount, token);
}
/**
* @notice Consumes inbound rate limiting capacity in this pool
*/
function _consumeInboundRateLimit(uint64 remoteChainSelector, address token, uint256 amount) internal {
s_inboundConfig[remoteChainSelector]._consume(amount, token);
}
function _setRateLimitConfig(
uint64 remoteChainSelector,
RateLimiter.Config memory outboundConfig,
RateLimiter.Config memory inboundConfig
) internal {
outboundConfig._validateTokenBucketConfig({mustBeDisabled: false});
s_outboundConfig[remoteChainSelector]._setTokenBucketConfig(outboundConfig);
inboundConfig._validateTokenBucketConfig({mustBeDisabled: false});
s_inboundConfig[remoteChainSelector]._setTokenBucketConfig(inboundConfig);
emit RateLimitConfigured(msg.sender, remoteChainSelector, outboundConfig, inboundConfig);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {AccessControlEnumerableUpgradeable} from
"@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";
import {ISharedStorageConsumer} from "src/interfaces/extensions/ISharedStorageConsumer.sol";
import {Error} from "src/libraries/Error.sol";
abstract contract SharedStorageConsumerUpgradeable is AccessControlEnumerableUpgradeable, ISharedStorageConsumer {
bytes32 public constant SHARED_STORAGE_SETTER_ROLE = keccak256("SHARED_STORAGE_SETTER_ROLE");
/// @dev Gap for future upgrades
uint256[50] private __gap1;
/// @dev Mapping of shared storage addresses to their allowed status
mapping(address sharedStorage => bool allowed) private s_sharedStorage;
/// @dev Gap for future upgrades
uint256[50] private __gap2;
function __SharedStorageConsumer_init(address sharedStorageSetter) internal onlyInitializing {
__SharedStorageConsumer_init_unchained(sharedStorageSetter);
}
function __SharedStorageConsumer_init_unchained(address sharedStorageSetter) internal onlyInitializing {
_grantRole(SHARED_STORAGE_SETTER_ROLE, sharedStorageSetter);
}
/**
* @inheritdoc ISharedStorageConsumer
*/
function setSharedStorage(address sharedStorage, bool shouldAdd) external onlyRole(SHARED_STORAGE_SETTER_ROLE) {
if (sharedStorage == address(0)) revert Error.ZeroAddressNotAllowed();
s_sharedStorage[sharedStorage] = shouldAdd;
emit SharedStorageUpdated(msg.sender, sharedStorage, shouldAdd);
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(ISharedStorageConsumer).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc ISharedStorageConsumer
*/
function isSharedStorage(address sharedStorage) public view returns (bool yes) {
return s_sharedStorage[sharedStorage];
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface ILockMintERC721Pool {
/// @dev Throws when ccip's message source chain selector does not match with decoded input.
error RemoteChainSelectorNotMatch(uint64 expected, uint64 actual);
/// @dev Throws when ccip's message original sender does not match with current pool config.
error RemotePoolNotMatch(address expected, address actual);
/// @dev Throws when failed to mint token.
error MintFailed(address minter, address to, uint256 id);
/// @dev Throws when failed to transfer token.
error ERC721TransferFailed(address recipient, uint256 id);
/// @dev Emit when successfully bridged nfts for user.
event CrossTransfer(
address indexed srcFrom,
address indexed dstTo,
bytes32 indexed messageId,
uint256[] ids,
uint64 srcChainSelector,
uint64 dstChainSelector
);
/**
* @dev Estimate the fee to pay for CCIP protocol to bridge the tokens.
* @param feeToken The token to pay the fee.
* @param remoteChainSelector The chain selector of the destination chain.
* @param tokenCount The number of tokens to bridge.
* @param gasLimit The gas limit for the transaction on the remote chain.
* @return fee The estimated fee in the feeToken.
*/
function estimateFee(address feeToken, uint64 remoteChainSelector, uint256 tokenCount, uint256 gasLimit)
external
view
returns (uint256 fee);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "../IAccessControl.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerable is IAccessControl {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.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 AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
struct AccessControlStorage {
mapping(bytes32 role => RoleData) _roles;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
assembly {
$.slot := AccessControlStorageLocation
}
}
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
/**
* @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 returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @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 returns (bytes32) {
AccessControlStorage storage $ = _getAccessControlStorage();
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 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 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 `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
AccessControlStorage storage $ = _getAccessControlStorage();
bytes32 previousAdminRole = getRoleAdmin(role);
$._roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (!hasRole(role, account)) {
$._roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (hasRole(role, account)) {
$._roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reinitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
*
* NOTE: Consider following the ERC-7201 formula to derive storage locations.
*/
function _initializableStorageSlot() internal pure virtual returns (bytes32) {
return INITIALIZABLE_STORAGE;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
bytes32 slot = _initializableStorageSlot();
assembly {
$.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice This interface contains the only RMN-related functions that might be used on-chain by other CCIP contracts.
interface IRMN {
/// @notice A Merkle root tagged with the address of the commit store contract it is destined for.
struct TaggedRoot {
address commitStore;
bytes32 root;
}
/// @notice Callers MUST NOT cache the return value as a blessed tagged root could become unblessed.
function isBlessed(
TaggedRoot calldata taggedRoot
) external view returns (bool);
/// @notice Iff there is an active global or legacy curse, this function returns true.
function isCursed() external view returns (bool);
/// @notice Iff there is an active global curse, or an active curse for `subject`, this function returns true.
/// @param subject To check whether a particular chain is cursed, set to bytes16(uint128(chainSelector)).
function isCursed(
bytes16 subject
) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
interface IWrappedNative is IERC20 {
function deposit() external payable;
function withdraw(
uint256 wad
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Client} from "../libraries/Client.sol";
/// @notice Application contracts that intend to receive messages from
/// the router should implement this interface.
interface IAny2EVMMessageReceiver {
/// @notice Called by the Router to deliver a message.
/// If this reverts, any token transfers also revert. The message
/// will move to a FAILED state and become available for manual execution.
/// @param message CCIP Message
/// @dev Note ensure you check the msg.sender is the OffRampRouter
function ccipReceive(
Client.Any2EVMMessage calldata message
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../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 An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @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.encodeCall(token.transfer, (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.encodeCall(token.transferFrom, (from, to, 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);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @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.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @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);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @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(token).code.length > 0;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
import {IRouter} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouter.sol";
interface IRouterClientExtended is IRouter, IRouterClient {
function getArmProxy() external view returns (address);
function getWrappedNative() external view returns (address);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {IPriceRegistry} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IPriceRegistry.sol";
interface IEVM2EVMOnRamp {
/// @dev Struct to contains the dynamic configuration
struct DynamicConfig {
address router; // ──────────────────────────╮ Router address
uint16 maxNumberOfTokensPerMsg; // │ Maximum number of distinct ERC20 token transferred per message
uint32 destGasOverhead; // │ Gas charged on top of the gasLimit to cover destination chain costs
uint16 destGasPerPayloadByte; // │ Destination chain gas charged for passing each byte of `data` payload to receiver
uint32 destDataAvailabilityOverheadGas; // ──╯ Extra data availability gas charged on top of the message, e.g. for OCR
uint16 destGasPerDataAvailabilityByte; // ───╮ Amount of gas to charge per byte of message data that needs availability
uint16 destDataAvailabilityMultiplierBps; // │ Multiplier for data availability gas, multiples of bps, or 0.0001
IPriceRegistry priceRegistry; // │ Price registry address
uint32 maxDataBytes; // │ Maximum payload data size in bytes
uint32 maxPerMsgGasLimit; // ────────────────╯ Maximum gas limit for messages targeting EVMs
// │
// The following three properties are defaults, they can be overridden by setting the TokenTransferFeeConfig for a token
uint16 defaultTokenFeeUSDCents; // ──────────╮ Default token fee charged per token transfer
uint32 defaultTokenDestGasOverhead; // │ Default gas charged to execute the token transfer on the destination chain
bool enforceOutOfOrder; // ──────────────────╯ Whether to enforce the allowOutOfOrderExecution extraArg value to be true.
}
function getDynamicConfig() external view returns (DynamicConfig memory dynamicConfig);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {IRMN} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRMN.sol";
import {IAny2EVMMessageReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IAny2EVMMessageReceiver.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IRouterClientExtended} from "src/interfaces/external/IRouterClientExtended.sol";
interface ICCIPSenderReceiver is IAny2EVMMessageReceiver, IERC165 {
/// @dev Revert if the remote chain is cursed by RMN.
error CursedByRMN();
/// @dev Revert if the sender is not enabled for the remote chain.
error SenderNotEnabled(uint64 chainSelector, address sender);
/// @dev Revert if the provided chain selector is current chain selector.
error OnlyRemoteChain(uint64 chainSelector);
/// @dev Revert if the provided chain selector is not current chain selector.
error OnlyLocalChain(uint64 chainSelector);
/// @dev Revert if the provided value is zero.
error ZeroValueNotAllowed();
/// @dev Revert if the provided address is not a valid router.
error InvalidRouter(address expected, address actual);
/// @dev Revert if the provided `chainSelector` is not enabled.
error NonExistentChain(uint64 chainSelector);
/// @dev Revert if the provided `chainSelector` is already enabled.
error ChainAlreadyEnabled(uint64 chainSelector);
/// @dev Revert if the provided `chainSelector` is not supported by CCIP router.
error ChainNotSupported(uint64 chainSelector);
/// @dev Revert if not allow receiving msg.value.
error MsgValueNotAllowed(uint256 value);
/// @dev Revert if failed to refund to the sender.
error RefundFailed(address to, uint256 value);
/// @dev Revert if provided fee is insufficient.
error InsufficientAllowance(uint256 expected, uint256 actual);
/// @dev Emit when refunded to the sender.
event Refunded(address indexed to, uint256 value);
/// @dev Emit when the message is sent to CCIP.
event MessageSent(address indexed by, bytes32 indexed messageId);
/// @dev Emit when the message is received from CCIP.
event MessageReceived(address by, bytes32 indexed messageId);
/// @dev Emit when the given `chainSelector` is disabled.
event RemoteChainDisabled(address indexed by, uint64 indexed chainSelector);
/// @dev Emit when the given `chainSelector` is enabled.
event RemoteChainEnabled(address indexed by, uint64 indexed chainSelector, address indexed remoteSender);
/*
* @dev Check whether the given `feeToken` is supported for the given `remoteChainSelector`.
*/
function isFeeTokenSupported(uint64 remoteChainSelector, address feeToken) external view returns (bool yes);
/*
* @dev Get all supported fee tokens for the given `remoteChainSelector`.
*/
function getFeeTokens(uint64 remoteChainSelector) external view returns (address[] memory feeTokens);
/*
* @dev Check whether given `chainSelector` is current chain selector.
*/
function isLocalChain(uint64 currentChainSelector) external view returns (bool yes);
/*
* @dev Check whether given `chainSelector` is supported by this contract.
*/
function isSupportedChain(uint64 remoteChainSelector) external view returns (bool yes);
/*
* @dev Get all supported chains for this contract.
*/
function getSupportedChains() external view returns (uint64[] memory remoteChainSelectors);
/*
* @dev Check whether the given `sender` is enabled for the given `remoteChainSelector`.
*/
function isSenderEnabled(uint64 remoteChainSelector, address sender) external view returns (bool yes);
/*
* @dev Get chain selector of the current chain.
*/
function getCurrentChainSelector() external view returns (uint64 currentChainSelector);
/*
* @dev Get CCIP router address.
*/
function getRouter() external view returns (IRouterClientExtended router);
/*
* @dev Get RMN proxy address.
*/
function getRmnProxy() external view returns (IRMN rmnProxy);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
library Error {
error ZeroAddressNotAllowed();
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.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 PausableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Pausable
struct PausableStorage {
bool _paused;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;
function _getPausableStorage() private pure returns (PausableStorage storage $) {
assembly {
$.slot := PausableStorageLocation
}
}
/**
* @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);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @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();
_;
}
function __Pausable_init() internal onlyInitializing {
}
function __Pausable_init_unchained() internal onlyInitializing {
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
PausableStorage storage $ = _getPausableStorage();
return $._paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
PausableStorage storage $ = _getPausableStorage();
$._paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface IPausable {
/**
* @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);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
function paused() external view returns (bool);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface IPausableExtended {
/**
* @dev Pauser role.
* Value is equal to keccak256("PAUSER_ROLE").
*/
function PAUSER_ROLE() external view returns (bytes32);
/**
* @dev Get global pauser address.
*/
function getGlobalPauser() external view returns (address globalPauser);
/**
* @dev Set global pauser address.
* Requirements:
* - The caller must have the DEFAULT_ADMIN_ROLE.
* @param globalPauser The address of the global pauser.
*/
function setGlobalPauser(address globalPauser) external;
/**
* @dev Pause the contract.
* Requirements:
* - The caller must have the PAUSER_ROLE.
*/
function pause() external;
/**
* @dev Unpause the contract.
* Requirements:
* - The caller must have the PAUSER_ROLE.
*/
function unpause() external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
/// @notice Implements Token Bucket rate limiting.
/// @dev uint128 is safe for rate limiter state.
/// For USD value rate limiting, it can adequately store USD value in 18 decimals.
/// For ERC20 token amount rate limiting, all tokens that will be listed will have at most
/// a supply of uint128.max tokens, and it will therefore not overflow the bucket.
/// In exceptional scenarios where tokens consumed may be larger than uint128,
/// e.g. compromised issuer, an enabled RateLimiter will check and revert.
library RateLimiter {
error BucketOverfilled();
error OnlyCallableByAdminOrOwner();
error TokenMaxCapacityExceeded(uint256 capacity, uint256 requested, address tokenAddress);
error TokenRateLimitReached(uint256 minWaitInSeconds, uint256 available, address tokenAddress);
error AggregateValueMaxCapacityExceeded(uint256 capacity, uint256 requested);
error AggregateValueRateLimitReached(uint256 minWaitInSeconds, uint256 available);
error InvalidRateLimitRate(Config rateLimiterConfig);
error DisabledNonZeroRateLimit(Config config);
error RateLimitMustBeDisabled();
event TokensConsumed(uint256 tokens);
event ConfigChanged(Config config);
struct TokenBucket {
uint128 tokens; // ──────╮ Current number of tokens that are in the bucket.
uint32 lastUpdated; // │ Timestamp in seconds of the last token refill, good for 100+ years.
bool isEnabled; // ──────╯ Indication whether the rate limiting is enabled or not
uint128 capacity; // ────╮ Maximum number of tokens that can be in the bucket.
uint128 rate; // ────────╯ Number of tokens per second that the bucket is refilled.
}
struct Config {
bool isEnabled; // Indication whether the rate limiting should be enabled
uint128 capacity; // ────╮ Specifies the capacity of the rate limiter
uint128 rate; // ───────╯ Specifies the rate of the rate limiter
}
/// @notice _consume removes the given tokens from the pool, lowering the
/// rate tokens allowed to be consumed for subsequent calls.
/// @param requestTokens The total tokens to be consumed from the bucket.
/// @param tokenAddress The token to consume capacity for, use 0x0 to indicate aggregate value capacity.
/// @dev Reverts when requestTokens exceeds bucket capacity or available tokens in the bucket
/// @dev emits removal of requestTokens if requestTokens is > 0
function _consume(TokenBucket storage s_bucket, uint256 requestTokens, address tokenAddress) internal {
// If there is no value to remove or rate limiting is turned off, skip this step to reduce gas usage
if (!s_bucket.isEnabled || requestTokens == 0) {
return;
}
uint256 tokens = s_bucket.tokens;
uint256 capacity = s_bucket.capacity;
uint256 timeDiff = block.timestamp - s_bucket.lastUpdated;
if (timeDiff != 0) {
if (tokens > capacity) revert BucketOverfilled();
// Refill tokens when arriving at a new block time
tokens = _calculateRefill(capacity, tokens, timeDiff, s_bucket.rate);
s_bucket.lastUpdated = uint32(block.timestamp);
}
if (capacity < requestTokens) {
// Token address 0 indicates consuming aggregate value rate limit capacity.
if (tokenAddress == address(0)) revert AggregateValueMaxCapacityExceeded(capacity, requestTokens);
revert TokenMaxCapacityExceeded(capacity, requestTokens, tokenAddress);
}
if (tokens < requestTokens) {
uint256 rate = s_bucket.rate;
// Wait required until the bucket is refilled enough to accept this value, round up to next higher second
// Consume is not guaranteed to succeed after wait time passes if there is competing traffic.
// This acts as a lower bound of wait time.
uint256 minWaitInSeconds = ((requestTokens - tokens) + (rate - 1)) / rate;
if (tokenAddress == address(0)) revert AggregateValueRateLimitReached(minWaitInSeconds, tokens);
revert TokenRateLimitReached(minWaitInSeconds, tokens, tokenAddress);
}
tokens -= requestTokens;
// Downcast is safe here, as tokens is not larger than capacity
s_bucket.tokens = uint128(tokens);
emit TokensConsumed(requestTokens);
}
/// @notice Gets the token bucket with its values for the block it was requested at.
/// @return The token bucket.
function _currentTokenBucketState(
TokenBucket memory bucket
) internal view returns (TokenBucket memory) {
// We update the bucket to reflect the status at the exact time of the
// call. This means we might need to refill a part of the bucket based
// on the time that has passed since the last update.
bucket.tokens =
uint128(_calculateRefill(bucket.capacity, bucket.tokens, block.timestamp - bucket.lastUpdated, bucket.rate));
bucket.lastUpdated = uint32(block.timestamp);
return bucket;
}
/// @notice Sets the rate limited config.
/// @param s_bucket The token bucket
/// @param config The new config
function _setTokenBucketConfig(TokenBucket storage s_bucket, Config memory config) internal {
// First update the bucket to make sure the proper rate is used for all the time
// up until the config change.
uint256 timeDiff = block.timestamp - s_bucket.lastUpdated;
if (timeDiff != 0) {
s_bucket.tokens = uint128(_calculateRefill(s_bucket.capacity, s_bucket.tokens, timeDiff, s_bucket.rate));
s_bucket.lastUpdated = uint32(block.timestamp);
}
s_bucket.tokens = uint128(_min(config.capacity, s_bucket.tokens));
s_bucket.isEnabled = config.isEnabled;
s_bucket.capacity = config.capacity;
s_bucket.rate = config.rate;
emit ConfigChanged(config);
}
/// @notice Validates the token bucket config
function _validateTokenBucketConfig(Config memory config, bool mustBeDisabled) internal pure {
if (config.isEnabled) {
if (config.rate >= config.capacity || config.rate == 0) {
revert InvalidRateLimitRate(config);
}
if (mustBeDisabled) {
revert RateLimitMustBeDisabled();
}
} else {
if (config.rate != 0 || config.capacity != 0) {
revert DisabledNonZeroRateLimit(config);
}
}
}
/// @notice Calculate refilled tokens
/// @param capacity bucket capacity
/// @param tokens current bucket tokens
/// @param timeDiff block time difference since last refill
/// @param rate bucket refill rate
/// @return the value of tokens after refill
function _calculateRefill(
uint256 capacity,
uint256 tokens,
uint256 timeDiff,
uint256 rate
) private pure returns (uint256) {
return _min(capacity, tokens + timeDiff * rate);
}
/// @notice Return the smallest of two integers
/// @param a first int
/// @param b second int
/// @return smallest
function _min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {RateLimiter} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/RateLimiter.sol";
interface IRateLimitConsumer {
/// @dev Emit when the rate limit is configured.
event RateLimitConfigured(
address indexed by,
uint64 indexed chainSelector,
RateLimiter.Config outboundConfig,
RateLimiter.Config inboundConfig
);
function RATE_LIMITER_ROLE() external view returns (bytes32);
/**
* @notice Sets the chain rate limiter config.
* @param remoteChainSelector The remote chain selector for which the rate limits apply.
* @param outboundConfig The new outbound rate limiter config, meaning the onRamp rate limits for the given chain.
* @param inboundConfig The new inbound rate limiter config, meaning the offRamp rate limits for the given chain.
*/
function setChainRateLimiterConfig(
uint64 remoteChainSelector,
RateLimiter.Config memory outboundConfig,
RateLimiter.Config memory inboundConfig
) external;
/**
* @notice Gets the token bucket with its values for the block it was requested at.
* @return state The token bucket.
*/
function getCurrentOutboundRateLimiterState(uint64 remoteChainSelector)
external
view
returns (RateLimiter.TokenBucket memory state);
/**
* @notice Gets the token bucket with its values for the block it was requested at.
* @return state The token bucket.
*/
function getCurrentInboundRateLimiterState(uint64 remoteChainSelector)
external
view
returns (RateLimiter.TokenBucket memory state);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
interface ISharedStorageConsumer {
/// @dev emit when shared storage is set.
event SharedStorageUpdated(address indexed sender, address indexed sharedStorage, bool shouldAdd);
/**
* @dev Sets the shared storage address. Used for pool to transferFrom
* @param sharedStorage The address of the shared storage contract.
* @param shouldAdd A boolean indicating whether to add or remove the shared storage.
*/
function setSharedStorage(address sharedStorage, bool shouldAdd) external;
/**
* @dev Shared storage setter role.
* Value is equal to keccak256("SHARED_STORAGE_SETTER_ROLE").
*/
function SHARED_STORAGE_SETTER_ROLE() external view returns (bytes32);
/**
* @dev Checks if the given address is a shared storage.
* @param sharedStorage The address to check.
* @return yes A boolean indicating whether the address is a shared storage.
*/
function isSharedStorage(address sharedStorage) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @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.
*/
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 `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 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);
* }
* ```
*/
abstract contract ERC165Upgradeable is Initializable, IERC165 {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.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 v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) 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 FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {Client} from "../libraries/Client.sol";
interface IRouterClient {
error UnsupportedDestinationChain(uint64 destChainSelector);
error InsufficientFeeTokenAmount();
error InvalidMsgValue();
/// @notice Checks if the given chain ID is supported for sending/receiving.
/// @param destChainSelector The chain to check.
/// @return supported is true if it is supported, false if not.
function isChainSupported(
uint64 destChainSelector
) external view returns (bool supported);
/// @param destinationChainSelector The destination chainSelector
/// @param message The cross-chain CCIP message including data and/or tokens
/// @return fee returns execution fee for the message
/// delivery to destination chain, denominated in the feeToken specified in the message.
/// @dev Reverts with appropriate reason upon invalid message.
function getFee(
uint64 destinationChainSelector,
Client.EVM2AnyMessage memory message
) external view returns (uint256 fee);
/// @notice Request a message to be sent to the destination chain
/// @param destinationChainSelector The destination chain ID
/// @param message The cross-chain CCIP message including data and/or tokens
/// @return messageId The message ID
/// @dev Note if msg.value is larger than the required fee (from getFee) we accept
/// the overpayment with no refund.
/// @dev Reverts with appropriate reason upon invalid message.
function ccipSend(
uint64 destinationChainSelector,
Client.EVM2AnyMessage calldata message
) external payable returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Client} from "../libraries/Client.sol";
interface IRouter {
error OnlyOffRamp();
/// @notice Route the message to its intended receiver contract.
/// @param message Client.Any2EVMMessage struct.
/// @param gasForCallExactCheck of params for exec
/// @param gasLimit set of params for exec
/// @param receiver set of params for exec
/// @dev if the receiver is a contracts that signals support for CCIP execution through EIP-165.
/// the contract is called. If not, only tokens are transferred.
/// @return success A boolean value indicating whether the ccip message was received without errors.
/// @return retBytes A bytes array containing return data form CCIP receiver.
/// @return gasUsed the gas used by the external customer call. Does not include any overhead.
function routeMessage(
Client.Any2EVMMessage calldata message,
uint16 gasForCallExactCheck,
uint256 gasLimit,
address receiver
) external returns (bool success, bytes memory retBytes, uint256 gasUsed);
/// @notice Returns the configured onramp for a specific destination chain.
/// @param destChainSelector The destination chain Id to get the onRamp for.
/// @return onRampAddress The address of the onRamp.
function getOnRamp(
uint64 destChainSelector
) external view returns (address onRampAddress);
/// @notice Return true if the given offRamp is a configured offRamp for the given source chain.
/// @param sourceChainSelector The source chain selector to check.
/// @param offRamp The address of the offRamp to check.
function isOffRamp(uint64 sourceChainSelector, address offRamp) external view returns (bool isOffRamp);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {Internal} from "../libraries/Internal.sol";
interface IPriceRegistry {
/// @notice Update the price for given tokens and gas prices for given chains.
/// @param priceUpdates The price updates to apply.
function updatePrices(
Internal.PriceUpdates memory priceUpdates
) external;
/// @notice Get the `tokenPrice` for a given token.
/// @param token The token to get the price for.
/// @return tokenPrice The tokenPrice for the given token.
function getTokenPrice(
address token
) external view returns (Internal.TimestampedPackedUint224 memory);
/// @notice Get the `tokenPrice` for a given token, checks if the price is valid.
/// @param token The token to get the price for.
/// @return tokenPrice The tokenPrice for the given token if it exists and is valid.
function getValidatedTokenPrice(
address token
) external view returns (uint224);
/// @notice Get the `tokenPrice` for an array of tokens.
/// @param tokens The tokens to get prices for.
/// @return tokenPrices The tokenPrices for the given tokens.
function getTokenPrices(
address[] calldata tokens
) external view returns (Internal.TimestampedPackedUint224[] memory);
/// @notice Get an encoded `gasPrice` for a given destination chain ID.
/// The 224-bit result encodes necessary gas price components.
/// On L1 chains like Ethereum or Avax, the only component is the gas price.
/// On Optimistic Rollups, there are two components - the L2 gas price, and L1 base fee for data availability.
/// On future chains, there could be more or differing price components.
/// PriceRegistry does not contain chain-specific logic to parse destination chain price components.
/// @param destChainSelector The destination chain to get the price for.
/// @return gasPrice The encoded gasPrice for the given destination chain ID.
function getDestinationChainGasPrice(
uint64 destChainSelector
) external view returns (Internal.TimestampedPackedUint224 memory);
/// @notice Gets the fee token price and the gas price, both denominated in dollars.
/// @param token The source token to get the price for.
/// @param destChainSelector The destination chain to get the gas price for.
/// @return tokenPrice The price of the feeToken in 1e18 dollars per base unit.
/// @return gasPrice The price of gas in 1e18 dollars per base unit.
function getTokenAndGasPrices(
address token,
uint64 destChainSelector
) external view returns (uint224 tokenPrice, uint224 gasPrice);
/// @notice Convert a given token amount to target token amount.
/// @param fromToken The given token address.
/// @param fromTokenAmount The given token amount.
/// @param toToken The target token address.
/// @return toTokenAmount The target token amount.
function convertTokenAmount(
address fromToken,
uint256 fromTokenAmount,
address toToken
) external view returns (uint256 toTokenAmount);
/// @notice Get the list of fee tokens.
/// @return feeTokens The tokens set as fee tokens.
function getFeeTokens() external view returns (address[] memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol";
import {Client} from "./Client.sol";
// Library for CCIP internal definitions common to multiple contracts.
library Internal {
error InvalidEVMAddress(bytes encodedAddress);
/// @dev The minimum amount of gas to perform the call with exact gas.
/// We include this in the offramp so that we can redeploy to adjust it
/// should a hardfork change the gas costs of relevant opcodes in callWithExactGas.
uint16 internal constant GAS_FOR_CALL_EXACT_CHECK = 5_000;
// @dev We limit return data to a selector plus 4 words. This is to avoid
// malicious contracts from returning large amounts of data and causing
// repeated out-of-gas scenarios.
uint16 internal constant MAX_RET_BYTES = 4 + 4 * 32;
/// @dev The expected number of bytes returned by the balanceOf function.
uint256 internal constant MAX_BALANCE_OF_RET_BYTES = 32;
/// @notice A collection of token price and gas price updates.
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct PriceUpdates {
TokenPriceUpdate[] tokenPriceUpdates;
GasPriceUpdate[] gasPriceUpdates;
}
/// @notice Token price in USD.
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct TokenPriceUpdate {
address sourceToken; // Source token
uint224 usdPerToken; // 1e18 USD per 1e18 of the smallest token denomination.
}
/// @notice Gas price for a given chain in USD, its value may contain tightly packed fields.
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct GasPriceUpdate {
uint64 destChainSelector; // Destination chain selector
uint224 usdPerUnitGas; // 1e18 USD per smallest unit (e.g. wei) of destination chain gas
}
/// @notice A timestamped uint224 value that can contain several tightly packed fields.
struct TimestampedPackedUint224 {
uint224 value; // ───────╮ Value in uint224, packed.
uint32 timestamp; // ────╯ Timestamp of the most recent price update.
}
/// @dev Gas price is stored in 112-bit unsigned int. uint224 can pack 2 prices.
/// When packing L1 and L2 gas prices, L1 gas price is left-shifted to the higher-order bits.
/// Using uint8 type, which cannot be higher than other bit shift operands, to avoid shift operand type warning.
uint8 public constant GAS_PRICE_BITS = 112;
struct PoolUpdate {
address token; // The IERC20 token address
address pool; // The token pool address
}
struct SourceTokenData {
// The source pool address, abi encoded. This value is trusted as it was obtained through the onRamp. It can be
// relied upon by the destination pool to validate the source pool.
bytes sourcePoolAddress;
// The address of the destination token, abi encoded in the case of EVM chains
// This value is UNTRUSTED as any pool owner can return whatever value they want.
bytes destTokenAddress;
// Optional pool data to be transferred to the destination chain. Be default this is capped at
// CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
// has to be set for the specific token.
bytes extraData;
uint32 destGasAmount; // The amount of gas available for the releaseOrMint and balanceOf calls on the offRamp
}
/// @notice Report that is submitted by the execution DON at the execution phase. (including chain selector data)
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct ExecutionReportSingleChain {
uint64 sourceChainSelector; // Source chain selector for which the report is submitted
Any2EVMRampMessage[] messages;
// Contains a bytes array for each message, each inner bytes array contains bytes per transferred token
bytes[][] offchainTokenData;
bytes32[] proofs;
uint256 proofFlagBits;
}
/// @notice Report that is submitted by the execution DON at the execution phase.
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct ExecutionReport {
EVM2EVMMessage[] messages;
// Contains a bytes array for each message, each inner bytes array contains bytes per transferred token
bytes[][] offchainTokenData;
bytes32[] proofs;
uint256 proofFlagBits;
}
/// @notice The cross chain message that gets committed to EVM chains.
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct EVM2EVMMessage {
uint64 sourceChainSelector; // ────────╮ the chain selector of the source chain, note: not chainId
address sender; // ────────────────────╯ sender address on the source chain
address receiver; // ──────────────────╮ receiver address on the destination chain
uint64 sequenceNumber; // ─────────────╯ sequence number, not unique across lanes
uint256 gasLimit; // user supplied maximum gas amount available for dest chain execution
bool strict; // ───────────────────────╮ DEPRECATED
uint64 nonce; // │ nonce for this lane for this sender, not unique across senders/lanes
address feeToken; // ──────────────────╯ fee token
uint256 feeTokenAmount; // fee token amount
bytes data; // arbitrary data payload supplied by the message sender
Client.EVMTokenAmount[] tokenAmounts; // array of tokens and amounts to transfer
bytes[] sourceTokenData; // array of token data, one per token
bytes32 messageId; // a hash of the message data
}
/// @dev EVM2EVMMessage struct has 13 fields, including 3 variable arrays.
/// Each variable array takes 1 more slot to store its length.
/// When abi encoded, excluding array contents,
/// EVM2EVMMessage takes up a fixed number of 16 lots, 32 bytes each.
/// For structs that contain arrays, 1 more slot is added to the front, reaching a total of 17.
uint256 public constant MESSAGE_FIXED_BYTES = 32 * 17;
/// @dev Each token transfer adds 1 EVMTokenAmount and 3 bytes at 3 slots each and one slot for the destGasAmount.
/// When abi encoded, each EVMTokenAmount takes 2 slots, each bytes takes 1 slot for length, one slot of data and one
/// slot for the offset. This results in effectively 3*3 slots per SourceTokenData.
/// 0x20
/// destGasAmount
/// sourcePoolAddress_offset
/// destTokenAddress_offset
/// extraData_offset
/// sourcePoolAddress_length
/// sourcePoolAddress_content // assume 1 slot
/// destTokenAddress_length
/// destTokenAddress_content // assume 1 slot
/// extraData_length // contents billed separately
uint256 public constant MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * ((1 + 3 * 3) + 2);
/// @dev Any2EVMRampMessage struct has 10 fields, including 3 variable unnested arrays (data, receiver and tokenAmounts).
/// Each variable array takes 1 more slot to store its length.
/// When abi encoded, excluding array contents,
/// Any2EVMMessage takes up a fixed number of 13 slots, 32 bytes each.
/// For structs that contain arrays, 1 more slot is added to the front, reaching a total of 14.
/// The fixed bytes does not cover struct data (this is represented by ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN)
uint256 public constant ANY_2_EVM_MESSAGE_FIXED_BYTES = 32 * 14;
/// @dev Each token transfer adds 1 RampTokenAmount
/// RampTokenAmount has 5 fields, 2 of which are bytes type, 1 Address, 1 uint256 and 1 uint32.
/// Each bytes type takes 1 slot for length, 1 slot for data and 1 slot for the offset.
/// address
/// uint256 amount takes 1 slot.
/// uint32 destGasAmount takes 1 slot.
uint256 public constant ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * ((2 * 3) + 3);
bytes32 internal constant EVM_2_EVM_MESSAGE_HASH = keccak256("EVM2EVMMessageHashV2");
/// @dev Used to hash messages for single-lane ramps.
/// OnRamp hash(EVM2EVMMessage) = OffRamp hash(EVM2EVMMessage)
/// The EVM2EVMMessage's messageId is expected to be the output of this hash function
/// @param original Message to hash
/// @param metadataHash Immutable metadata hash representing a lane with a fixed OnRamp
/// @return hashedMessage hashed message as a keccak256
function _hash(EVM2EVMMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
// Fixed-size message fields are included in nested hash to reduce stack pressure.
// This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.
return keccak256(
abi.encode(
MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
metadataHash,
keccak256(
abi.encode(
original.sender,
original.receiver,
original.sequenceNumber,
original.gasLimit,
original.strict,
original.nonce,
original.feeToken,
original.feeTokenAmount
)
),
keccak256(original.data),
keccak256(abi.encode(original.tokenAmounts)),
keccak256(abi.encode(original.sourceTokenData))
)
);
}
bytes32 internal constant ANY_2_EVM_MESSAGE_HASH = keccak256("Any2EVMMessageHashV1");
bytes32 internal constant EVM_2_ANY_MESSAGE_HASH = keccak256("EVM2AnyMessageHashV1");
/// @dev Used to hash messages for multi-lane family-agnostic OffRamps.
/// OnRamp hash(EVM2AnyMessage) != Any2EVMRampMessage.messageId
/// OnRamp hash(EVM2AnyMessage) != OffRamp hash(Any2EVMRampMessage)
/// @param original OffRamp message to hash
/// @param metadataHash Hash preimage to ensure global uniqueness
/// @return hashedMessage hashed message as a keccak256
function _hash(Any2EVMRampMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
// Fixed-size message fields are included in nested hash to reduce stack pressure.
// This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.
return keccak256(
abi.encode(
MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
metadataHash,
keccak256(
abi.encode(
original.header.messageId,
original.receiver,
original.header.sequenceNumber,
original.gasLimit,
original.header.nonce
)
),
keccak256(original.sender),
keccak256(original.data),
keccak256(abi.encode(original.tokenAmounts))
)
);
}
function _hash(EVM2AnyRampMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
// Fixed-size message fields are included in nested hash to reduce stack pressure.
// This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.
return keccak256(
abi.encode(
MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
metadataHash,
keccak256(
abi.encode(
original.sender,
original.header.sequenceNumber,
original.header.nonce,
original.feeToken,
original.feeTokenAmount
)
),
keccak256(original.receiver),
keccak256(original.data),
keccak256(abi.encode(original.tokenAmounts)),
keccak256(original.extraArgs)
)
);
}
/// @dev We disallow the first 1024 addresses to avoid calling into a range known for hosting precompiles. Calling
/// into precompiles probably won't cause any issues, but to be safe we can disallow this range. It is extremely
/// unlikely that anyone would ever be able to generate an address in this range. There is no official range of
/// precompiles, but EIP-7587 proposes to reserve the range 0x100 to 0x1ff. Our range is more conservative, even
/// though it might not be exhaustive for all chains, which is OK. We also disallow the zero address, which is a
/// common practice.
uint256 public constant PRECOMPILE_SPACE = 1024;
/// @notice This methods provides validation for parsing abi encoded addresses by ensuring the
/// address is within the EVM address space. If it isn't it will revert with an InvalidEVMAddress error, which
/// we can catch and handle more gracefully than a revert from abi.decode.
/// @return The address if it is valid, the function will revert otherwise.
function _validateEVMAddress(
bytes memory encodedAddress
) internal pure returns (address) {
if (encodedAddress.length != 32) revert InvalidEVMAddress(encodedAddress);
uint256 encodedAddressUint = abi.decode(encodedAddress, (uint256));
if (encodedAddressUint > type(uint160).max || encodedAddressUint < PRECOMPILE_SPACE) {
revert InvalidEVMAddress(encodedAddress);
}
return address(uint160(encodedAddressUint));
}
/// @notice Enum listing the possible message execution states within
/// the offRamp contract.
/// UNTOUCHED never executed
/// IN_PROGRESS currently being executed, used a replay protection
/// SUCCESS successfully executed. End state
/// FAILURE unsuccessfully executed, manual execution is now enabled.
/// @dev RMN depends on this enum, if changing, please notify the RMN maintainers.
enum MessageExecutionState {
UNTOUCHED,
IN_PROGRESS,
SUCCESS,
FAILURE
}
/// @notice CCIP OCR plugin type, used to separate execution & commit transmissions and configs
enum OCRPluginType {
Commit,
Execution
}
/// @notice Family-agnostic header for OnRamp & OffRamp messages.
/// The messageId is not expected to match hash(message), since it may originate from another ramp family
struct RampMessageHeader {
bytes32 messageId; // Unique identifier for the message, generated with the source chain's encoding scheme (i.e. not necessarily abi.encoded)
uint64 sourceChainSelector; // ──╮ the chain selector of the source chain, note: not chainId
uint64 destChainSelector; // | the chain selector of the destination chain, note: not chainId
uint64 sequenceNumber; // │ sequence number, not unique across lanes
uint64 nonce; // ────────────────╯ nonce for this lane for this sender, not unique across senders/lanes
}
struct EVM2AnyTokenTransfer {
// The source pool EVM address. This value is trusted as it was obtained through the onRamp. It can be
// relied upon by the destination pool to validate the source pool.
address sourcePoolAddress;
// The EVM address of the destination token
// This value is UNTRUSTED as any pool owner can return whatever value they want.
bytes destTokenAddress;
// Optional pool data to be transferred to the destination chain. Be default this is capped at
// CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
// has to be set for the specific token.
bytes extraData;
uint256 amount; // Amount of tokens.
// Destination chain specific execution data encoded in bytes
// for an EVM destination, it consists of the amount of gas available for the releaseOrMint
// and transfer calls made by the offRamp
bytes destExecData;
}
struct Any2EVMTokenTransfer {
// The source pool EVM address encoded to bytes. This value is trusted as it is obtained through the onRamp. It can be
// relied upon by the destination pool to validate the source pool.
bytes sourcePoolAddress;
address destTokenAddress; // ───╮ Address of destination token
uint32 destGasAmount; //────────╯ The amount of gas available for the releaseOrMint and transfer calls on the offRamp.
// Optional pool data to be transferred to the destination chain. Be default this is capped at
// CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
// has to be set for the specific token.
bytes extraData;
uint256 amount; // Amount of tokens.
}
/// @notice Family-agnostic message routed to an OffRamp
/// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage), hash(Any2EVMRampMessage) != messageId
/// due to encoding & parameter differences
struct Any2EVMRampMessage {
RampMessageHeader header; // Message header
bytes sender; // sender address on the source chain
bytes data; // arbitrary data payload supplied by the message sender
address receiver; // receiver address on the destination chain
uint256 gasLimit; // user supplied maximum gas amount available for dest chain execution
Any2EVMTokenTransfer[] tokenAmounts; // array of tokens and amounts to transfer
}
/// @notice Family-agnostic message emitted from the OnRamp
/// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage) due to encoding & parameter differences
/// messageId = hash(EVM2AnyRampMessage) using the source EVM chain's encoding format
struct EVM2AnyRampMessage {
RampMessageHeader header; // Message header
address sender; // sender address on the source chain
bytes data; // arbitrary data payload supplied by the message sender
bytes receiver; // receiver address on the destination chain
bytes extraArgs; // destination-chain specific extra args, such as the gasLimit for EVM chains
address feeToken; // fee token
uint256 feeTokenAmount; // fee token amount
uint256 feeValueJuels; // fee amount in Juels
EVM2AnyTokenTransfer[] tokenAmounts; // array of tokens and amounts to transfer
}
// bytes4(keccak256("CCIP ChainFamilySelector EVM"))
bytes4 public constant CHAIN_FAMILY_SELECTOR_EVM = 0x2812d52c;
/// @dev Struct to hold a merkle root and an interval for a source chain so that an array of these can be passed in the CommitReport.
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
/// @dev ineffiecient struct packing intentionally chosen to maintain order of specificity. Not a storage struct so impact is minimal.
// solhint-disable-next-line gas-struct-packing
struct MerkleRoot {
uint64 sourceChainSelector; // Remote source chain selector that the Merkle Root is scoped to
bytes onRampAddress; // Generic onramp address, to support arbitrary sources; for EVM, use abi.encode
uint64 minSeqNr; // ─────────────╮ Minimum sequence number, inclusive
uint64 maxSeqNr; // ─────────────╯ Maximum sequence number, inclusive
bytes32 merkleRoot; // Merkle root covering the interval & source chain messages
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
library MerkleMultiProof {
/// @notice Leaf domain separator, should be used as the first 32 bytes of a leaf's preimage.
bytes32 internal constant LEAF_DOMAIN_SEPARATOR = 0x0000000000000000000000000000000000000000000000000000000000000000;
/// @notice Internal domain separator, should be used as the first 32 bytes of an internal node's preiimage.
bytes32 internal constant INTERNAL_DOMAIN_SEPARATOR =
0x0000000000000000000000000000000000000000000000000000000000000001;
uint256 internal constant MAX_NUM_HASHES = 256;
error InvalidProof();
error LeavesCannotBeEmpty();
/// @notice Computes the root based on provided pre-hashed leaf nodes in
/// leaves, internal nodes in proofs, and using proofFlagBits' i-th bit to
/// determine if an element of proofs or one of the previously computed leafs
/// or internal nodes will be used for the i-th hash.
/// @param leaves Should be pre-hashed and the first 32 bytes of a leaf's
/// preimage should match LEAF_DOMAIN_SEPARATOR.
/// @param proofs The hashes to be used instead of a leaf hash when the proofFlagBits
/// indicates a proof should be used.
/// @param proofFlagBits A single uint256 of which each bit indicates whether a leaf or
/// a proof needs to be used in a hash operation.
/// @dev the maximum number of hash operations it set to 256. Any input that would require
/// more than 256 hashes to get to a root will revert.
/// @dev For given input `leaves` = [a,b,c] `proofs` = [D] and `proofFlagBits` = 5
/// totalHashes = 3 + 1 - 1 = 3
/// ** round 1 **
/// proofFlagBits = (5 >> 0) & 1 = true
/// hashes[0] = hashPair(a, b)
/// (leafPos, hashPos, proofPos) = (2, 0, 0);
///
/// ** round 2 **
/// proofFlagBits = (5 >> 1) & 1 = false
/// hashes[1] = hashPair(D, c)
/// (leafPos, hashPos, proofPos) = (3, 0, 1);
///
/// ** round 3 **
/// proofFlagBits = (5 >> 2) & 1 = true
/// hashes[2] = hashPair(hashes[0], hashes[1])
/// (leafPos, hashPos, proofPos) = (3, 2, 1);
///
/// i = 3 and no longer < totalHashes. The algorithm is done
/// return hashes[totalHashes - 1] = hashes[2]; the last hash we computed.
// We mark this function as internal to force it to be inlined in contracts
// that use it, but semantically it is public.
// solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
function merkleRoot(
bytes32[] memory leaves,
bytes32[] memory proofs,
uint256 proofFlagBits
) internal pure returns (bytes32) {
unchecked {
uint256 leavesLen = leaves.length;
uint256 proofsLen = proofs.length;
if (leavesLen == 0) revert LeavesCannotBeEmpty();
if (!(leavesLen <= MAX_NUM_HASHES + 1 && proofsLen <= MAX_NUM_HASHES + 1)) revert InvalidProof();
uint256 totalHashes = leavesLen + proofsLen - 1;
if (!(totalHashes <= MAX_NUM_HASHES)) revert InvalidProof();
if (totalHashes == 0) {
return leaves[0];
}
bytes32[] memory hashes = new bytes32[](totalHashes);
(uint256 leafPos, uint256 hashPos, uint256 proofPos) = (0, 0, 0);
for (uint256 i = 0; i < totalHashes; ++i) {
// Checks if the bit flag signals the use of a supplied proof or a leaf/previous hash.
bytes32 a;
if (proofFlagBits & (1 << i) == (1 << i)) {
// Use a leaf or a previously computed hash.
if (leafPos < leavesLen) {
a = leaves[leafPos++];
} else {
a = hashes[hashPos++];
}
} else {
// Use a supplied proof.
a = proofs[proofPos++];
}
// The second part of the hashed pair is never a proof as hashing two proofs would result in a
// hash that can already be computed offchain.
bytes32 b;
if (leafPos < leavesLen) {
b = leaves[leafPos++];
} else {
b = hashes[hashPos++];
}
if (!(hashPos <= i)) revert InvalidProof();
hashes[i] = _hashPair(a, b);
}
if (!(hashPos == totalHashes - 1 && leafPos == leavesLen && proofPos == proofsLen)) revert InvalidProof();
// Return the last hash.
return hashes[totalHashes - 1];
}
}
/// @notice Hashes two bytes32 objects in their given order, prepended by the
/// INTERNAL_DOMAIN_SEPARATOR.
function _hashInternalNode(bytes32 left, bytes32 right) private pure returns (bytes32 hash) {
return keccak256(abi.encode(INTERNAL_DOMAIN_SEPARATOR, left, right));
}
/// @notice Hashes two bytes32 objects. The order is taken into account,
/// using the lower value first.
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _hashInternalNode(a, b) : _hashInternalNode(b, a);
}
}{
"remappings": [
"@chainlink/contracts-ccip/=lib/ccip/contracts/",
"@chainlink/contracts/=lib/chainlink-brownie-contracts/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@solady/=lib/solady/src/",
"ccip/=lib/ccip/contracts/",
"chainlink-brownie-contracts/=lib/chainlink-brownie-contracts/contracts/src/v0.6/vendor/@arbitrum/nitro-contracts/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solady/=lib/solady/src/"
],
"optimizer": {
"enabled": true,
"runs": 10
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"}],"name":"AggregateValueMaxCapacityExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"minWaitInSeconds","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"AggregateValueRateLimitReached","type":"error"},{"inputs":[],"name":"BucketOverfilled","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"ChainAlreadyEnabled","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"ChainNotSupported","type":"error"},{"inputs":[],"name":"CursedByRMN","type":"error"},{"inputs":[{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"config","type":"tuple"}],"name":"DisabledNonZeroRateLimit","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ERC721TransferFailed","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"rateLimiterConfig","type":"tuple"}],"name":"InvalidRateLimitRate","type":"error"},{"inputs":[{"internalType":"address","name":"expected","type":"address"},{"internalType":"address","name":"actual","type":"address"}],"name":"InvalidRouter","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"LengthMismatch","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"MessageIdAlreadyExists","type":"error"},{"inputs":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"MintFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"MsgValueNotAllowed","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"NonExistentChain","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"OnlyLocalChain","type":"error"},{"inputs":[],"name":"OnlyLocalToken","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"OnlyRemoteChain","type":"error"},{"inputs":[],"name":"RateLimitMustBeDisabled","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"RefundFailed","type":"error"},{"inputs":[{"internalType":"uint64","name":"expected","type":"uint64"},{"internalType":"uint64","name":"actual","type":"uint64"}],"name":"RemoteChainSelectorNotMatch","type":"error"},{"inputs":[{"internalType":"address","name":"expected","type":"address"},{"internalType":"address","name":"actual","type":"address"}],"name":"RemotePoolNotMatch","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"address","name":"sender","type":"address"}],"name":"SenderNotEnabled","type":"error"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"address","name":"remoteToken","type":"address"}],"name":"TokenAlreadyMapped","type":"error"},{"inputs":[{"internalType":"uint256","name":"capacity","type":"uint256"},{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenMaxCapacityExceeded","type":"error"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"TokenNotMapped","type":"error"},{"inputs":[{"internalType":"uint256","name":"minWaitInSeconds","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"TokenRateLimitReached","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"inputs":[],"name":"ZeroValueNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"config","type":"tuple"}],"name":"ConfigChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"srcFrom","type":"address"},{"indexed":true,"internalType":"address","name":"dstTo","type":"address"},{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint64","name":"srcChainSelector","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"dstChainSelector","type":"uint64"}],"name":"CrossTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint32","name":"fixedGas","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"dynamicGas","type":"uint32"}],"name":"GasLimitConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"MessageReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"}],"name":"MessageSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"chainSelector","type":"uint64"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"outboundConfig","type":"tuple"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"indexed":false,"internalType":"struct RateLimiter.Config","name":"inboundConfig","type":"tuple"}],"name":"RateLimitConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Refunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"RemoteChainDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"chainSelector","type":"uint64"},{"indexed":true,"internalType":"address","name":"remoteSender","type":"address"}],"name":"RemoteChainEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"indexed":true,"internalType":"address","name":"remotePool","type":"address"}],"name":"RemotePoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"RemotePoolRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"indexed":true,"internalType":"address","name":"localToken","type":"address"},{"indexed":false,"internalType":"address","name":"remoteToken","type":"address"}],"name":"RemoteTokenMapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":true,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"indexed":true,"internalType":"address","name":"localToken","type":"address"}],"name":"RemoteTokenUnmapped","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":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"sharedStorage","type":"address"},{"indexed":false,"internalType":"bool","name":"shouldAdd","type":"bool"}],"name":"SharedStorageUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"TokensConsumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATE_LIMITER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARED_STORAGE_SETTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_POOL_OWNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"remotePool","type":"address"}],"name":"addRemotePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes","name":"sender","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"destTokenAmounts","type":"tuple[]"}],"internalType":"struct Client.Any2EVMMessage","name":"message","type":"tuple"}],"name":"ccipReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"crossBatchTransfer","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"crossTransfer","outputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"uint256","name":"tokenCount","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"estimateFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentChainSelector","outputs":[{"internalType":"uint64","name":"currentChainSelector","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getCurrentInboundRateLimiterState","outputs":[{"components":[{"internalType":"uint128","name":"tokens","type":"uint128"},{"internalType":"uint32","name":"lastUpdated","type":"uint32"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.TokenBucket","name":"state","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getCurrentOutboundRateLimiterState","outputs":[{"components":[{"internalType":"uint128","name":"tokens","type":"uint128"},{"internalType":"uint32","name":"lastUpdated","type":"uint32"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.TokenBucket","name":"state","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getFeeTokens","outputs":[{"internalType":"address[]","name":"feeTokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGlobalPauser","outputs":[{"internalType":"address","name":"globalPauser","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getMessageIds","outputs":[{"internalType":"uint256","name":"length","type":"uint256"},{"internalType":"bytes32[]","name":"messageIds","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getRemotePool","outputs":[{"internalType":"address","name":"remotePool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRemotePools","outputs":[{"internalType":"uint64[]","name":"remoteChainSelectors","type":"uint64[]"},{"internalType":"address[]","name":"remotePools","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getRemoteToken","outputs":[{"internalType":"address","name":"remoteToken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRmnProxy","outputs":[{"internalType":"contract IRMN","name":"rmnProxy","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":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMembers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRouter","outputs":[{"internalType":"contract IRouterClientExtended","name":"router","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupportedChains","outputs":[{"internalType":"uint64[]","name":"remoteChainSelectors","type":"uint64[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"getSupportedTokensForChain","outputs":[{"internalType":"address[]","name":"localTokens","type":"address[]"},{"internalType":"address[]","name":"remoteTokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokens","outputs":[{"internalType":"address[]","name":"localTokens","type":"address[]"}],"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":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint64","name":"currentChainSelector","type":"uint64"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"feeToken","type":"address"}],"name":"isFeeTokenSupported","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"currentChainSelector","type":"uint64"}],"name":"isLocalChain","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"sender","type":"address"}],"name":"isSenderEnabled","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sharedStorage","type":"address"}],"name":"isSharedStorage","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"isSupportedChain","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"}],"name":"isSupportedToken","outputs":[{"internalType":"bool","name":"yes","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"address","name":"remoteToken","type":"address"}],"name":"mapRemoteToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"removeRemotePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"outboundConfig","type":"tuple"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint128","name":"capacity","type":"uint128"},{"internalType":"uint128","name":"rate","type":"uint128"}],"internalType":"struct RateLimiter.Config","name":"inboundConfig","type":"tuple"}],"name":"setChainRateLimiterConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"globalPauser","type":"address"}],"name":"setGlobalPauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sharedStorage","type":"address"},{"internalType":"bool","name":"shouldAdd","type":"bool"}],"name":"setSharedStorage","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":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"localToken","type":"address"},{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"}],"name":"unmapRemoteToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"localTokens","type":"address[]"},{"internalType":"address[]","name":"tos","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"withdrawLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6080604052348015600e575f5ffd5b5060156019565b60c9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560685760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b614fce806100d65f395ff3fe608060405260043610610243575f3560e01c8063017e25e31461024757806301ffc9a71461026857806307a40f0b1461029c5780630a2fd493146102bb578063181f5a77146102e757806320cf81231461033c578063240028e81461035b578063248a9ca31461037a5780632e86678f146103a75780632f2ff15d146103c65780632faa5dc7146103e55780633195ac8314610404578063322cfeda1461043057806333fbf7191461044f57806336568abe1461046e5780633ab9e4921461048d5780633f4ba83a146104a05780633fd8c1b5146104b457806346e28a09146104e157806356b5440c146105005780635c975abb1461052d5780636b0e4f86146105415780636e15e242146105605780637879ec311461057d5780638456cb591461059c57806385572ffb146105b05780638926f54f146105cf5780638bdd6d8e146105ee5780638f20071d1461060e5780639010d07c1461063d57806391d148541461065c5780639bc53a201461067b578063a217fddf1461069a578063a3246ad3146106ad578063aa6ca808146106cc578063af58d59f146106e0578063b0f479a114610752578063bb0edba014610770578063bd9421e11461078f578063c4bffe2b146107ae578063c75eea9c146107cf578063ca15c873146107ee578063cf7401f31461080d578063d3bd04f11461082c578063d547741f1461083f578063d6111d861461085e578063db87d27814610880578063dc0bd971146108a0578063e60d6462146108c5578063e63ab1e9146108e5578063eab2c75714610905575b5f5ffd5b348015610252575f5ffd5b50610266610261366004614037565b610926565b005b348015610273575f5ffd5b50610287610282366004614052565b610996565b60405190151581526020015b60405180910390f35b3480156102a7575f5ffd5b506102666102b6366004614086565b6109cf565b3480156102c6575f5ffd5b506102da6102d53660046140d3565b610a6f565b60405161029391906140ec565b3480156102f2575f5ffd5b5061032f6040518060400160405280601d81526020017f4d756c74694c6f636b4d696e74455243373231506f6f6c20312e302e3000000081525081565b604051610293919061412e565b348015610347575f5ffd5b50610266610356366004614140565b610a79565b348015610366575f5ffd5b50610287610375366004614037565b610adf565b348015610385575f5ffd5b5061039961039436600461416a565b610b67565b604051908152602001610293565b3480156103b2575f5ffd5b506102666103c1366004614181565b610b85565b3480156103d1575f5ffd5b506102666103e03660046141c7565b610c21565b3480156103f0575f5ffd5b506102666103ff3660046140d3565b610c43565b34801561040f575f5ffd5b5061042361041e3660046140d3565b610c9c565b604051610293919061422d565b34801561043b575f5ffd5b5061039961044a36600461423f565b610de4565b34801561045a575f5ffd5b506102666104693660046142c7565b610ebb565b348015610479575f5ffd5b506102666104883660046141c7565b611022565b61039961049b366004614363565b611055565b3480156104ab575f5ffd5b50610266611077565b3480156104bf575f5ffd5b506104d36104ce3660046143cd565b611099565b6040516102939291906143fd565b3480156104ec575f5ffd5b506102876104fb366004614037565b6111a5565b34801561050b575f5ffd5b5061051f61051a3660046140d3565b6111c2565b60405161029392919061444a565b348015610538575f5ffd5b50610287611357565b34801561054c575f5ffd5b5061028761055b366004614140565b61140c565b34801561056b575f5ffd5b506032546001600160a01b03166102da565b348015610588575f5ffd5b5061026661059736600461446e565b61144e565b3480156105a7575f5ffd5b50610266611573565b3480156105bb575f5ffd5b506102666105ca3660046144b2565b611592565b3480156105da575f5ffd5b506102876105e93660046140d3565b611632565b3480156105f9575f5ffd5b506103995f516020614f195f395f51905f5281565b348015610619575f5ffd5b506102876106283660046140d3565b610162546001600160401b0391821691161490565b348015610648575f5ffd5b506102da6106573660046144e8565b6116bf565b348015610667575f5ffd5b506102876106763660046141c7565b6116eb565b348015610686575f5ffd5b506102da610695366004614508565b61171f565b3480156106a5575f5ffd5b506103995f81565b3480156106b8575f5ffd5b506104236106c736600461416a565b611768565b3480156106d7575f5ffd5b5061042361178c565b3480156106eb575f5ffd5b506106ff6106fa3660046140d3565b611880565b604051610293919081516001600160801b03908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b34801561075d575f5ffd5b50610163546001600160a01b03166102da565b34801561077b575f5ffd5b5061026661078a366004614508565b611906565b34801561079a575f5ffd5b506102876107a9366004614140565b611977565b3480156107b9575f5ffd5b506107c26119f4565b6040516102939190614574565b3480156107da575f5ffd5b506106ff6107e93660046140d3565b611b32565b3480156107f9575f5ffd5b5061039961080836600461416a565b611bb8565b348015610818575f5ffd5b5061026661082736600461459c565b611bdb565b61039961083a3660046145d5565b611c19565b34801561084a575f5ffd5b506102666108593660046141c7565b611c68565b348015610869575f5ffd5b50610872611c84565b604051610293929190614666565b34801561088b575f5ffd5b506103995f516020614f595f395f51905f5281565b3480156108ab575f5ffd5b5061016254600160401b90046001600160a01b03166102da565b3480156108d0575f5ffd5b506103995f516020614f395f395f51905f5281565b3480156108f0575f5ffd5b506103995f516020614f795f395f51905f5281565b348015610910575f5ffd5b50610919611d3c565b6040516102939190614678565b5f61093081611d4c565b603280546001600160a01b0319166001600160a01b03841690811790915561097b57603254610976905f516020614f795f395f51905f52906001600160a01b0316611d56565b505050565b6109765f516020614f795f395f51905f5283611d95565b5050565b5f6001600160e01b03198216636d7f8bbd60e11b14806109ba57506109ba82611dcb565b806109c957506109c982611e1c565b92915050565b5f516020614f595f395f51905f526109e681611d4c565b6001600160a01b038316610a0d576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0383165f81815260fd6020908152604091829020805460ff1916861515908117909155915191825233917f613ecbe5e56592771e18a638a133dc61a4488af23ac95580246a6dfa5edf240291015b60405180910390a3505050565b5f6109c982611e40565b5f516020614f195f395f51905f52610a9081611d4c565b610a9a8383611e7a565b6040516001600160a01b038316906001600160401b0385169033907f9f60ea76bb48f63c19a3d1bc23acb2a57138cbf18441efefe59a3d0c124d93ac905f90a4505050565b5f610aec61023183611fe5565b610af757505f919050565b5f610b006119f4565b80519091505f5b81811015610b5d575f6001600160a01b0316610b3c86858481518110610b2f57610b2f61468c565b602002602001015161171f565b6001600160a01b031614610b5557506001949350505050565b600101610b07565b505f949350505050565b5f5f610b71611ff9565b5f9384526020525050604090206001015490565b5f516020614f195f395f51905f52610b9c81611d4c565b83610ba68161201d565b83610bb081612044565b610bb98461201d565b610bc486868661206c565b856001600160a01b0316856001600160401b0316336001600160a01b03167feea3add3a72bfdec05437019247fe0e77d59874c7ae83510efc39677e14f9aa087604051610c1191906140ec565b60405180910390a4505050505050565b610c2a82610b67565b610c3381611d4c565b610c3d8383611d95565b50505050565b5f516020614f195f395f51905f52610c5a81611d4c565b610c6382612155565b6040516001600160401b0383169033907faf18d5efc97c08e5572a2feab86f2b1200f9ccceac5f451c0cce5d00822c5010905f90a35050565b606081610ca881612044565b6101635460405163a8d87a3b60e01b81526001600160a01b039091169063a8d87a3b90610cd9908690600401614678565b602060405180830381865afa158015610cf4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d1891906146ab565b6001600160a01b0316637437ff9f6040518163ffffffff1660e01b81526004016101a060405180830381865afa158015610d54573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d789190614784565b60e001516001600160a01b031663cdc73d516040518163ffffffff1660e01b81526004015f60405180830381865afa158015610db6573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ddd91908101906148a9565b9392505050565b6040805160c0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820152836001600160401b03811115610e2b57610e2b6146c6565b604051908082528060200260200182016040528015610e54578160200160208202803683370190505b50604051602001610e65919061496d565b60408051601f1981840301815291905260a0820152610eb085610e8781610a6f565b83604051602001610e98919061497f565b6040516020818303038152906040528660018b6121d9565b509695505050505050565b5f610ec581611d4c565b85610ed0818461238a565b610eda818661238a565b610ee3816123b4565b5f5b8181101561101757610f1c898983818110610f0257610f0261468c565b9050602002016020810190610f179190614037565b6123d4565b610f4b878783818110610f3157610f3161468c565b9050602002016020810190610f469190614037565b61201d565b888882818110610f5d57610f5d61468c565b9050602002016020810190610f729190614037565b6001600160a01b03166323b872dd30898985818110610f9357610f9361468c565b9050602002016020810190610fa89190614037565b888886818110610fba57610fba61468c565b905060200201356040518463ffffffff1660e01b8152600401610fdf939291906149ec565b5f604051808303815f87803b158015610ff6575f5ffd5b505af1158015611008573d5f5f3e3d5ffd5b50505050806001019050610ee5565b505050505050505050565b6001600160a01b038116331461104b5760405163334bd91960e11b815260040160405180910390fd5b6109768282611d56565b5f61106c878787611065886123fa565b8787612440565b979650505050505050565b5f516020614f795f395f51905f5261108e81611d4c565b611096612568565b50565b6001600160401b0383165f9081526101cb602052604090205460608184106110cf5750604080515f81526020810190915261119d565b816110da8486614a24565b11156110ed576110ea8483614a37565b92505b826001600160401b03811115611105576111056146c6565b60405190808252806020026020018201604052801561112e578160200160208202803683370190505b5090505f5b8381101561119b576001600160401b0386165f9081526101cb6020526040902061115d8287614a24565b8154811061116d5761116d61468c565b905f5260205f2001548282815181106111885761118861468c565b6020908102919091010152600101611133565b505b935093915050565b6001600160a01b03165f90815260fd602052604090205460ff1690565b6060806111ce83611632565b6111ef575050604080515f8082526020820190815281830190925292909150565b5f6111fb6102316125be565b9050806001600160401b03811115611215576112156146c6565b60405190808252806020026020018201604052801561123e578160200160208202803683370190505b509250806001600160401b03811115611259576112596146c6565b604051908082528060200260200182016040528015611282578160200160208202803683370190505b5091505f5f5b82811015611349575f61129d610231836125c7565b6001600160a01b038082165f908152610233602090815260408083206001600160401b038d16845290915290205491925016801561133f57818785815181106112e8576112e861468c565b60200260200101906001600160a01b031690816001600160a01b0316815250508086858151811061131b5761131b61468c565b6001600160a01b039092166020928302919091019091015261133c84614a4a565b93505b5050600101611288565b508084528083525050915091565b6032545f906001600160a01b031661137c5f516020614f795f395f51905f52826116eb565b801561139157506001600160a01b0381163b15155b80156113f85750806001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113d4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113f89190614a62565b8061140657506114066125d2565b91505090565b5f61141683611632565b61142157505f6109c9565b506001600160401b03919091165f90815261016660205260409020546001600160a01b0390811691161490565b5f6114576125e6565b805490915060ff600160401b82041615906001600160401b03165f8115801561147d5750825b90505f826001600160401b031660011480156114985750303b155b9050811580156114a6575080155b156114c45760405163f92ee8a960e01b815260040160405180910390fd5b84546001600160401b031916600117855583156114ed57845460ff60401b1916600160401b1785555b6114f75f89611d95565b506115018861260e565b61150a8861261f565b61151388612630565b61151e888888612641565b831561156957845460ff60401b191685556040517fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29061156090600190614678565b60405180910390a15b5050505050505050565b5f516020614f795f395f51905f5261158a81611d4c565b61109661265c565b6115a260408201602083016140d3565b6115ab816126a2565b5f6115b96040840184614a7d565b8101906115c69190614037565b90506115e16115db60408501602086016140d3565b82612741565b6115e9612782565b6115f2836127c0565b825f01357fce0ee41dd56ba56504e3cbb18167239f0ff664e41824e710d406e710e3ed0a388260405161162591906140ec565b60405180910390a2505050565b5f6116486101646001600160401b038416612957565b80156109c9575061016354604051631491520b60e31b81526001600160a01b039091169063a48a905890611680908590600401614678565b602060405180830381865afa15801561169b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109c99190614a62565b5f5f6116c9612962565b5f8581526020829052604090209091506116e390846125c7565b949350505050565b5f5f6116f5611ff9565b5f948552602090815260408086206001600160a01b03959095168652939052505090205460ff1690565b5f61172982611632565b61173457505f6109c9565b506001600160a01b039182165f908152610233602090815260408083206001600160401b0394909416835292905220541690565b60605f611773612962565b5f848152602082905260409020909150610ddd90612986565b60605f61179a610231612986565b8051909150806001600160401b038111156117b7576117b76146c6565b6040519080825280602002602001820160405280156117e0578160200160208202803683370190505b5092505f5f5b82811015611876576118108482815181106118035761180361468c565b6020026020010151610adf565b1561186e578381815181106118275761182761468c565b602002602001015185838061183b90614a4a565b94508151811061184d5761184d61468c565b60200260200101906001600160a01b031690816001600160a01b0316815250505b6001016117e6565b5080845250505090565b611888613fe6565b6001600160401b0382165f90815260986020908152604091829020825160a08101845281546001600160801b038082168352600160801b80830463ffffffff1695840195909552600160a01b90910460ff1615159482019490945260019091015480841660608301529190910490911660808201526109c990612992565b5f516020614f195f395f51905f5261191d81611d4c565b8161192781612044565b61193184846129fc565b6040516001600160a01b038516906001600160401b0385169033907f1397d60c55aea4f977e36de26ece59e6c1111bb420cc66e2d9565bc475bf82ef905f90a450505050565b5f5f61198284610c9c565b80519091505f819003611999575f925050506109c9565b5f5b818110156119e957846001600160a01b03168382815181106119bf576119bf61468c565b60200260200101516001600160a01b0316036119e157600193505050506109c9565b60010161199b565b505f95945050505050565b60605f611a02610164612986565b8051909150806001600160401b03811115611a1f57611a1f6146c6565b604051908082528060200260200182016040528015611a48578160200160208202803683370190505b5092505f5f5b82811015611876575f848281518110611a6957611a6961468c565b602090810291909101015161016354604051631491520b60e31b81529192506001600160a01b03169063a48a905890611aa6908490600401614678565b602060405180830381865afa158015611ac1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ae59190614a62565b15611b2957808684611af681614a4a565b955081518110611b0857611b0861468c565b60200260200101906001600160401b031690816001600160401b0316815250505b50600101611a4e565b611b3a613fe6565b6001600160401b0382165f90815260976020908152604091829020825160a08101845281546001600160801b038082168352600160801b80830463ffffffff1695840195909552600160a01b90910460ff1615159482019490945260019091015480841660608301529190910490911660808201526109c990612992565b5f5f611bc2612962565b5f848152602082905260409020909150610ddd906125be565b5f516020614f395f395f51905f52611bf281611d4c565b610c3d84611c0536869003860186614ad5565b611c1436869003860186614ad5565b612ab6565b5f611c5c8888888888808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152508a92508991506124409050565b98975050505050505050565b611c7182610b67565b611c7a81611d4c565b610c3d8383611d56565b606080611c8f6119f4565b8051909250806001600160401b03811115611cac57611cac6146c6565b604051908082528060200260200182016040528015611cd5578160200160208202803683370190505b5091505f5b81811015611d3657611d04848281518110611cf757611cf761468c565b6020026020010151610a6f565b838281518110611d1657611d1661468c565b6001600160a01b0390921660209283029190910190910152600101611cda565b50509091565b610162546001600160401b031690565b6110968133612b51565b5f5f611d60612962565b90505f611d6d8585612b7c565b905080156116e3575f858152602083905260409020611d8c9085612bfb565b50949350505050565b5f5f611d9f612962565b90505f611dac8585612c0f565b905080156116e3575f858152602083905260409020611d8c9085612ca4565b5f6001600160e01b031982166319167f6d60e11b1480611def5750611def82612cb8565b80611dfe5750611dfe82612cf7565b80611e0d5750611e0d82612d17565b806109c957506109c982612d37565b5f6001600160e01b031982166319c7358960e21b14806109c957506109c982612cb8565b5f611e4a82611632565b611e5557505f919050565b506001600160401b03165f90815261016660205260409020546001600160a01b031690565b611e838161201d565b610162546001600160401b0390811690831603611ebe578160405163af86032f60e01b8152600401611eb59190614678565b60405180910390fd5b61016354604051631491520b60e31b81526001600160a01b039091169063a48a905890611eef908590600401614678565b602060405180830381865afa158015611f0a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f2e9190614a62565b611f4d578160405163172ced9d60e11b8152600401611eb59190614678565b611f626101646001600160401b038416612d5b565b611f815781604051632f2c07d760e01b8152600401611eb59190614678565b6001600160401b0382165f818152610166602052604080822080546001600160a01b0319166001600160a01b038616908117909155905190929133917f8de8fd9740da5fc201a38a6085490fd6dfc07ce3a73938627eac66a5e748cefb9190a45050565b5f610ddd836001600160a01b038416612d66565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680090565b6001600160a01b038116611096576040516342bcdf7f60e11b815260040160405180910390fd5b61204d81611632565b6110965780604051631e670e4b60e01b8152600401611eb59190614678565b5f5f612077846111c2565b8051919350915015612100575f5b81518110156120fe57836001600160a01b03168282815181106120aa576120aa61468c565b60200260200101516001600160a01b0316036120f6578281815181106120d2576120d261468c565b602002602001015184604051631cfa01f360e11b8152600401611eb5929190614b42565b600101612085565b505b61210c61023186612ca4565b5050506001600160a01b039283165f908152610233602090815260408083206001600160401b039590951683529390529190912080546001600160a01b03191691909216179055565b61216a6101646001600160401b038316612d7d565b6121895780604051631e670e4b60e01b8152600401611eb59190614678565b6001600160401b0381165f818152610166602052604080822080546001600160a01b03191690555133917fb7c3517ce5cb1b2e820e49d7850f4e0e71cde55b70c0995bab3b7eafe3abc87291a350565b5f6122146040518060a001604052806060815260200160608152602001606081526020015f6001600160a01b03168152602001606081525090565b8761221e81612044565b6040805160a08101909152806122378a60c083016140ec565b60408051808303601f1901815291815290825260208083018b905281515f808252918101835292909101919061228e565b604080518082019091525f80825260208201528152602001906001900390816122685790505b508152602001856001600160a01b0316815260200161230760405180604001604052808a81526020018915158152506040805182516024820152602092830151151560448083019190915282518083039091018152606490910190915290810180516001600160e01b0316630181dcf160e41b17905290565b9052610163546040516320487ded60e01b81529193506001600160a01b0316906320487ded9061233d908c908690600401614b5c565b602060405180830381865afa158015612358573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061237c9190614c2e565b925050965096945050505050565b808214610992576040516355c5b3e360e11b81526004810183905260248101829052604401611eb5565b805f036110965760405163273e150360e21b815260040160405180910390fd5b6123dd81610adf565b6110965760405163f850ff3b60e01b815260040160405180910390fd5b6040805160018082528183019092526060916020808301908036833701905050905081815f8151811061242f5761242f61468c565b602002602001018181525050919050565b5f8461244b8161201d565b5f8560405160200161245d919061496d565b60408051601f198184030181526060830182526001600160401b038b1683526001600160a01b038c166020840152908201819052915061249c90612d88565b5f6124a78a8a61171f565b90506124b28161201d565b612548896124bf8b610a6f565b6040518060c00160405280336001600160a01b031681526020016124e1611d3c565b6001600160401b031681526020018c6001600160a01b03168152602001856001600160a01b03168152602001306001600160a01b0316815260200186815250604051602001612530919061497f565b6040516020818303038152906040528860018b612e88565b935061255b612555611d3c565b856131f7565b5050509695505050505050565b61257061329f565b5f6125796132c4565b805460ff1916815590507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516125b391906140ec565b60405180910390a150565b5f6109c9825490565b5f610ddd83836132e8565b5f5f6125dc6132c4565b5460ff1692915050565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a006109c9565b61261661330e565b61109681613333565b61262761330e565b6110968161336d565b61263861330e565b6110968161338c565b61264961330e565b612652836133ab565b61097682826133ca565b6126646133dc565b5f61266d6132c4565b805460ff1916600117815590507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125a63390565b61016254604051632cbc26bb60e01b8152608083901b600160801b600160c01b03166004820152600160401b9091046001600160a01b031690632cbc26bb90602401602060405180830381865afa1580156126ff573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127239190614a62565b1561109657604051630a75a23b60e31b815260040160405180910390fd5b61274b828261140c565b6109925760405163d5079a3560e01b81526001600160401b03831660048201526001600160a01b0382166024820152604401611eb5565b610163546001600160a01b031633146127be5761016354604051637ec1982b60e01b8152611eb5916001600160a01b0316903390600401614b42565b565b5f6127ce6060830183614a7d565b8101906127db9190614cb0565b905080602001516001600160401b03168260200160208101906127fe91906140d3565b6001600160401b03161461284d5761281c60408301602084016140d3565b6020820151604051638428f1f760e01b81526001600160401b03928316600482015291166024820152604401611eb5565b5f61285b6040840184614a7d565b8101906128689190614037565b905081608001516001600160a01b0316816001600160a01b0316146128a75760808201516040516310c4624f60e21b8152611eb5918391600401614b42565b81516128b29061201d565b60208201516128c29084356131f7565b6128cb82613402565b825f013582604001516001600160a01b0316835f01516001600160a01b03167f55e75798c6b341acacc33826c47c58fccf851dda1790809862e7299fe1874d448560a001518060200190518101906129239190614d75565b6129336040890160208a016140d3565b61293b611d3c565b60405161294a93929190614dfb565b60405180910390a4505050565b5f610ddd8383612d66565b7fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e8237170593200090565b60605f610ddd83613420565b61299a613fe6565b6129e182606001516001600160801b0316835f01516001600160801b0316846020015163ffffffff16426129ce9190614a37565b85608001516001600160801b0316613479565b6001600160801b031682525063ffffffff4216602082015290565b6001600160a01b038083165f908152610233602090815260408083206001600160401b03861684529091529020541680612a6357604051639bc50b1760e01b81526001600160a01b03841660048201526001600160401b0383166024820152604401611eb5565b6001600160a01b0383165f908152610233602090815260408083206001600160401b0386168452909152902080546001600160a01b0319169055612aa683610adf565b61097657610c3d61023184612bfb565b612ac0825f6134a0565b6001600160401b0383165f908152609760205260409020612ae19083613561565b612aeb815f6134a0565b6001600160401b0383165f908152609860205260409020612b0c9082613561565b826001600160401b0316336001600160a01b03167f3a6cd4bdc00dc992306b6d7795432a8934d7c9fbdb85b49faad03dad43c817248484604051610a62929190614e57565b612b5b82826116eb565b61099257808260405163e2517d3f60e01b8152600401611eb5929190614e72565b5f5f612b86611ff9565b9050612b9284846116eb565b15612bf2575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a460019150506109c9565b5f9150506109c9565b5f610ddd836001600160a01b03841661367a565b5f5f612c19611ff9565b9050612c2584846116eb565b612bf2575f848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055612c5a3390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a460019150506109c9565b5f610ddd836001600160a01b038416613754565b5f6001600160e01b0319821663181f5a7760e01b1480612ce857506001600160e01b0319821663d6d62d0d60e01b145b806109c957506109c98261379b565b5f6001600160e01b03198216634d60abbd60e11b14806109c957506109c9825b5f6001600160e01b031982166320bfad4960e11b14806109c957506109c9825b5f6001600160e01b0319821663324c152b60e01b14806109c957506109c9826137eb565b5f610ddd8383613754565b5f9081526001919091016020526040902054151590565b5f610ddd838361367a565b612d906133dc565b8060200151612d9e816123d4565b8151612da981612044565b5f8360400151806020019051810190612dc29190614d75565b8051909150612dd0816123b4565b5f5b81811015612e5f5785602001516001600160a01b03166323b872dd3330868581518110612e0157612e0161468c565b60200260200101516040518463ffffffff1660e01b8152600401612e27939291906149ec565b5f604051808303815f87803b158015612e3e575f5ffd5b505af1158015612e50573d5f5f3e3d5ffd5b50505050806001019050612dd2565b50612e6f8560200151308461380f565b612e81855f0151866020015183613894565b5050505050565b5f86612e93816126a2565b612e9c8761201d565b612ea5856123b4565b612eaf86516123b4565b5f5f612ebf8a8a8a8a8a8a6121d9565b90925090505f6001600160a01b038616612ff55782341015612efd5760405163054365bb60e31b815260048101849052346024820152604401611eb5565b6101635f9054906101000a90046001600160a01b03166001600160a01b031663e861e9076040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f4e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f7291906146ab565b95508582606001906001600160a01b031690816001600160a01b031681525050856001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004015f604051808303818588803b158015612fcb575f5ffd5b505af1158015612fdd573d5f5f3e3d5ffd5b50505050508234612fee9190614a37565b905061302b565b3415613016576040516336334e4560e01b8152346004820152602401611eb5565b61302b6001600160a01b0387163330866138b6565b6101635460405163095ea7b360e01b81526001600160a01b038881169263095ea7b39261306092909116908790600401614e72565b6020604051808303815f875af115801561307c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130a09190614a62565b50610163546040516396f4e9f960e01b81526001600160a01b03909116906396f4e9f9906130d4908e908690600401614b5c565b6020604051808303815f875af11580156130f0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131149190614c2e565b945080156131bd576040515f90339083908381818185875af1925050503d805f811461315b576040519150601f19603f3d011682016040523d82523d5f602084013e613160565b606091505b50509050806131865733826040516357b9d85960e11b8152600401611eb5929190614e72565b60405182815233907fd7dee2702d63ad89917b6a4da9981c90c4d24f8c2bdfd64c604ecae57d8d06519060200160405180910390a2505b604051859033907fb06a7d56e5736d613c3122470fadaf19fa9b76fbc2244c4ed1bab9c2c4d6213b905f90a3505050509695505050505050565b6001600160401b0382165f9081526101cc6020908152604080832084845290915290205460ff161561324e576040516342cb76b360e11b81526001600160401b038316600482015260248101829052604401611eb5565b6001600160401b039091165f8181526101cb60209081526040808320805460018181018355918552838520018690559383526101cc825280832094835293905291909120805460ff19169091179055565b6132a7611357565b6127be57604051638dfc202b60e01b815260040160405180910390fd5b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330090565b5f825f0182815481106132fd576132fd61468c565b905f5260205f200154905092915050565b613316613910565b6127be57604051631afcd79f60e31b815260040160405180910390fd5b61333b61330e565b603280546001600160a01b0319166001600160a01b0383161790556109925f516020614f795f395f51905f5282611d95565b61337561330e565b6109925f516020614f395f395f51905f5282611d95565b61339461330e565b6109925f516020614f595f395f51905f5282611d95565b6133b361330e565b6109925f516020614f195f395f51905f5282611d95565b6133d261330e565b6109928282613929565b6133e4611357565b156127be5760405163d93c066560e01b815260040160405180910390fd5b613417610f468260600151836020015161171f565b61109681613a04565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561346d57602002820191905f5260205f20905b815481526020019060010190808311613459575b50505050509050919050565b5f613497856134888486614e8b565b6134929087614a24565b613ba4565b95945050505050565b81511561351a5781602001516001600160801b031682604001516001600160801b03161015806134db575060408201516001600160801b0316155b156134fb5781604051632008344960e21b8152600401611eb59190614ea2565b80156109925760405163433fc33d60e01b815260040160405180910390fd5b60408201516001600160801b0316151580613541575060208201516001600160801b031615155b1561099257816040516335a2be7360e21b8152600401611eb59190614ea2565b81545f9061357c90600160801b900463ffffffff1642614a37565b905080156135da57600183015483546135ae916001600160801b03808216928116918591600160801b90910416613479565b83546001600160801b03919091166001600160a01b031990911617600160801b4263ffffffff16021783555b602082015183546135f7916001600160801b039081169116613ba4565b835483511515600160a01b02600164ff0000000160801b03199091166001600160801b039283161717845560208301516040808501518316600160801b0291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c199061366d908490614ea2565b60405180910390a1505050565b5f8181526001830160205260408120548015612bf2575f61369c600183614a37565b85549091505f906136af90600190614a37565b905080821461370e575f865f0182815481106136cd576136cd61468c565b905f5260205f200154905080875f0184815481106136ed576136ed61468c565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061371f5761371f614eb0565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506109c9565b5f61375f8383612d66565b61379457508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556109c9565b505f6109c9565b5f6001600160e01b031982166351fdd48d60e11b14806137cb57506001600160e01b031982166385572ffb60e01b145b806109c957506001600160e01b031982166301ffc9a760e01b1492915050565b5f6001600160e01b03198216635a05180f60e01b14806109c957506109c982613bb9565b80515f5b81811015612e8157836001600160a01b03166138488685848151811061383b5761383b61468c565b6020026020010151613bed565b6001600160a01b03161461388c57838382815181106138695761386961468c565b6020026020010151604051631cc2e71960e31b8152600401611eb5929190614e72565b600101613813565b6001600160401b0383165f908152609760205260409020610976908284613c62565b610c3d84856001600160a01b03166323b872dd8686866040516024016138de939291906149ec565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050613e73565b5f6139196125e6565b54600160401b900460ff16919050565b61393161330e565b613943816001600160401b03166123b4565b61016380546001600160a01b0319166001600160a01b03841690811790915560408051635246492f60e01b81529051635246492f916004808201926020929091908290030181865afa15801561399b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139bf91906146ab565b61016280546001600160401b039093166001600160401b03196001600160a01b0393909316600160401b02929092166001600160e01b03199093169290921717905550565b613a0c6133dc565b5f8160a00151806020019051810190613a259190614d75565b8051909150613a33816123b4565b613a40836040015161201d565b613a4d83606001516123d4565b5f5b81811015613b7d575f838281518110613a6a57613a6a61468c565b602002602001015190505f613a83866060015183613bed565b90506001600160a01b038116301480613aa05750613aa0816111a5565b15613b0f5785606001516001600160a01b03166323b872dd828860400151856040518463ffffffff1660e01b8152600401613add939291906149ec565b5f604051808303815f87803b158015613af4575f5ffd5b505af1158015613b06573d5f5f3e3d5ffd5b50505050613b73565b85606001516001600160a01b03166340c10f198760400151846040518363ffffffff1660e01b8152600401613b45929190614e72565b5f604051808303815f87803b158015613b5c575f5ffd5b505af1158015613b6e573d5f5f3e3d5ffd5b505050505b5050600101613a4f565b50613b91836060015184604001518461380f565b6109768360200151846060015183613ecb565b5f818310613bb25781610ddd565b5090919050565b5f6001600160e01b03198216637965db0b60e01b14806109c957506301ffc9a760e01b6001600160e01b03198316146109c9565b6040516331a9108f60e11b8152600481018290525f906001600160a01b03841690636352211e90602401602060405180830381865afa925050508015613c50575060408051601f3d908101601f19168201909252613c4d918101906146ab565b60015b613c5b57505f6109c9565b90506109c9565b8254600160a01b900460ff161580613c78575081155b15613c8257505050565b825460018401546001600160801b03808316929116905f90613cb190600160801b900463ffffffff1642614a37565b90508015613d1d5781831115613cda57604051634b92ca1560e11b815260040160405180910390fd5b6001860154613cfe90839085908490600160801b90046001600160801b0316613479565b865463ffffffff60801b1916600160801b4263ffffffff160217875592505b84821015613d75576001600160a01b038416613d565760405163f94ebcd160e01b81526004810183905260248101869052604401611eb5565b818585604051630d3b2b9560e11b8152600401611eb593929190614ec4565b84831015613e1257600186810154600160801b90046001600160801b0316905f908290613da29082614a37565b613dac878a614a37565b613db69190614a24565b613dc09190614ee3565b90506001600160a01b038616613df3576040516302a4f38160e31b81526004810182905260248101869052604401611eb5565b808587604051636864691d60e11b8152600401611eb593929190614ec4565b613e1c8584614a37565b86546001600160801b0319166001600160801b0382161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b5f613e876001600160a01b03841683613eed565b905080515f14158015613eab575080806020019051810190613ea99190614a62565b155b156109765782604051635274afe760e01b8152600401611eb591906140ec565b6001600160401b0383165f908152609860205260409020610976908284613c62565b6060610ddd83835f845f5f856001600160a01b03168486604051613f119190614f02565b5f6040518083038185875af1925050503d805f8114613f4b576040519150601f19603f3d011682016040523d82523d5f602084013e613f50565b606091505b5091509150613f60868383613f6a565b9695505050505050565b606082613f7f57613f7a82613fbd565b610ddd565b8151158015613f9657506001600160a01b0384163b155b15613fb65783604051639996b31560e01b8152600401611eb591906140ec565b5080610ddd565b805115613fcd5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6040805160a0810182525f8082526020820181905291810182905260608101829052608081019190915290565b6001600160a01b0381168114611096575f5ffd5b803561403281614013565b919050565b5f60208284031215614047575f5ffd5b8135610ddd81614013565b5f60208284031215614062575f5ffd5b81356001600160e01b031981168114610ddd575f5ffd5b8015158114611096575f5ffd5b5f5f60408385031215614097575f5ffd5b82356140a281614013565b915060208301356140b281614079565b809150509250929050565b80356001600160401b0381168114614032575f5ffd5b5f602082840312156140e3575f5ffd5b610ddd826140bd565b6001600160a01b0391909116815260200190565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610ddd6020830184614100565b5f5f60408385031215614151575f5ffd5b61415a836140bd565b915060208301356140b281614013565b5f6020828403121561417a575f5ffd5b5035919050565b5f5f5f60608486031215614193575f5ffd5b833561419e81614013565b92506141ac602085016140bd565b915060408401356141bc81614013565b809150509250925092565b5f5f604083850312156141d8575f5ffd5b8235915060208301356140b281614013565b5f8151808452602084019350602083015f5b828110156142235781516001600160a01b03168652602095860195909101906001016141fc565b5093949350505050565b602081525f610ddd60208301846141ea565b5f5f5f5f60808587031215614252575f5ffd5b843561425d81614013565b935061426b602086016140bd565b93969395505050506040820135916060013590565b5f5f83601f840112614290575f5ffd5b5081356001600160401b038111156142a6575f5ffd5b6020830191508360208260051b85010111156142c0575f5ffd5b9250929050565b5f5f5f5f5f5f606087890312156142dc575f5ffd5b86356001600160401b038111156142f1575f5ffd5b6142fd89828a01614280565b90975095505060208701356001600160401b0381111561431b575f5ffd5b61432789828a01614280565b90955093505060408701356001600160401b03811115614345575f5ffd5b61435189828a01614280565b979a9699509497509295939492505050565b5f5f5f5f5f5f60c08789031215614378575f5ffd5b863561438381614013565b9550614391602088016140bd565b945060408701356143a181614013565b93506060870135925060808701356143b881614013565b9598949750929591949360a090920135925050565b5f5f5f606084860312156143df575f5ffd5b6143e8846140bd565b95602085013595506040909401359392505050565b5f60408201848352604060208401528084518083526060850191506020860192505f5b8181101561443e578351835260209384019390920191600101614420565b50909695505050505050565b604081525f61445c60408301856141ea565b828103602084015261349781856141ea565b5f5f5f60608486031215614480575f5ffd5b833561448b81614013565b9250602084013561449b81614013565b91506144a9604085016140bd565b90509250925092565b5f602082840312156144c2575f5ffd5b81356001600160401b038111156144d7575f5ffd5b820160a08185031215610ddd575f5ffd5b5f5f604083850312156144f9575f5ffd5b50508035926020909101359150565b5f5f60408385031215614519575f5ffd5b823561452481614013565b9150614532602084016140bd565b90509250929050565b5f8151808452602084019350602083015f5b828110156142235781516001600160401b031686526020958601959091019060010161454d565b602081525f610ddd602083018461453b565b5f60608284031215614596575f5ffd5b50919050565b5f5f5f60e084860312156145ae575f5ffd5b6145b7846140bd565b92506145c68560208601614586565b91506144a98560808601614586565b5f5f5f5f5f5f5f60c0888a0312156145eb575f5ffd5b87356145f681614013565b9650614604602089016140bd565b9550604088013561461481614013565b945060608801356001600160401b0381111561462e575f5ffd5b61463a8a828b01614280565b909550935050608088013561464e81614013565b96999598509396929591949193505060a09091013590565b604081525f61445c604083018561453b565b6001600160401b0391909116815260200190565b634e487b7160e01b5f52603260045260245ffd5b805161403281614013565b5f602082840312156146bb575f5ffd5b8151610ddd81614013565b634e487b7160e01b5f52604160045260245ffd5b6040516101a081016001600160401b03811182821017156146fd576146fd6146c6565b60405290565b60405160c081016001600160401b03811182821017156146fd576146fd6146c6565b604051601f8201601f191681016001600160401b038111828210171561474d5761474d6146c6565b604052919050565b805161ffff81168114614032575f5ffd5b805163ffffffff81168114614032575f5ffd5b805161403281614079565b5f6101a0828403128015614796575f5ffd5b5061479f6146da565b6147a8836146a0565b81526147b660208401614755565b60208201526147c760408401614766565b60408201526147d860608401614755565b60608201526147e960808401614766565b60808201526147fa60a08401614755565b60a082015261480b60c08401614755565b60c082015261481c60e084016146a0565b60e082015261482e6101008401614766565b6101008201526148416101208401614766565b6101208201526148546101408401614755565b6101408201526148676101608401614766565b61016082015261487a6101808401614779565b6101808201529392505050565b5f6001600160401b0382111561489f5761489f6146c6565b5060051b60200190565b5f602082840312156148b9575f5ffd5b81516001600160401b038111156148ce575f5ffd5b8201601f810184136148de575f5ffd5b80516148f16148ec82614887565b614725565b8082825260208201915060208360051b850101925086831115614912575f5ffd5b6020840193505b82841015613f6057835161492c81614013565b825260209384019390910190614919565b5f8151808452602084019350602083015f5b8281101561422357815186526020958601959091019060010161494f565b602081525f610ddd602083018461493d565b602080825282516001600160a01b0390811683830152908301516001600160401b0316604080840191909152830151811660608084019190915283015181166080808401919091528301511660a08083019190915282015160c0808301525f906116e360e0840182614100565b6001600160a01b039384168152919092166020820152604081019190915260600190565b634e487b7160e01b5f52601160045260245ffd5b808201808211156109c9576109c9614a10565b818103818111156109c9576109c9614a10565b5f60018201614a5b57614a5b614a10565b5060010190565b5f60208284031215614a72575f5ffd5b8151610ddd81614079565b5f5f8335601e19843603018112614a92575f5ffd5b8301803591506001600160401b03821115614aab575f5ffd5b6020019150368190038213156142c0575f5ffd5b80356001600160801b0381168114614032575f5ffd5b5f6060828403128015614ae6575f5ffd5b50604051606081016001600160401b0381118282101715614b0957614b096146c6565b6040528235614b1781614079565b8152614b2560208401614abf565b6020820152614b3660408401614abf565b60408201529392505050565b6001600160a01b0392831681529116602082015260400190565b60018060401b0383168152604060208201525f825160a06040840152614b8560e0840182614100565b90506020840151603f19848303016060850152614ba28282614100565b6040860151858203603f190160808701528051808352602091820194505f93509101905b80831015614bfd57835180516001600160a01b03168352602090810151818401529093019260019290920191604090910190614bc6565b5060608601516001600160a01b031660a08601526080860151858203603f190160c0870152925061106c8184614100565b5f60208284031215614c3e575f5ffd5b5051919050565b5f82601f830112614c54575f5ffd5b81356001600160401b03811115614c6d57614c6d6146c6565b614c80601f8201601f1916602001614725565b818152846020838601011115614c94575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60208284031215614cc0575f5ffd5b81356001600160401b03811115614cd5575f5ffd5b820160c08185031215614ce6575f5ffd5b614cee614703565b8135614cf981614013565b8152614d07602083016140bd565b60208201526040820135614d1a81614013565b60408201526060820135614d2d81614013565b6060820152614d3e60808301614027565b608082015260a08201356001600160401b03811115614d5b575f5ffd5b614d6786828501614c45565b60a083015250949350505050565b5f60208284031215614d85575f5ffd5b81516001600160401b03811115614d9a575f5ffd5b8201601f81018413614daa575f5ffd5b8051614db86148ec82614887565b8082825260208201915060208360051b850101925086831115614dd9575f5ffd5b6020840193505b82841015613f60578351825260209384019390910190614de0565b606081525f614e0d606083018661493d565b6001600160401b0394851660208401529290931660409091015292915050565b8051151582526020808201516001600160801b039081169184019190915260409182015116910152565b60c08101614e658285614e2d565b610ddd6060830184614e2d565b6001600160a01b03929092168252602082015260400190565b80820281158282048414176109c9576109c9614a10565b606081016109c98284614e2d565b634e487b7160e01b5f52603160045260245ffd5b92835260208301919091526001600160a01b0316604082015260600190565b5f82614efd57634e487b7160e01b5f52601260045260245ffd5b500490565b5f82518060208501845e5f92019182525091905056fe9562977e123fbe4558c4ac6a21f5c0a7f5ee8c1bd1bb59ec24cd079022975cb815975e67e85433b86162c65eeaf7d19d2b619671751d1f6d4d320dc195d465db1688c00bd4b3d5d2661432cff443a73d99517e416fd98c1425d800f7b6b0b9e965d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aa2646970667358221220bba0137ca3101440e2b76765b14e4154ddbde848a7797d09aa47ff6d4820a23064736f6c634300081d0033
Deployed Bytecode
0x608060405260043610610243575f3560e01c8063017e25e31461024757806301ffc9a71461026857806307a40f0b1461029c5780630a2fd493146102bb578063181f5a77146102e757806320cf81231461033c578063240028e81461035b578063248a9ca31461037a5780632e86678f146103a75780632f2ff15d146103c65780632faa5dc7146103e55780633195ac8314610404578063322cfeda1461043057806333fbf7191461044f57806336568abe1461046e5780633ab9e4921461048d5780633f4ba83a146104a05780633fd8c1b5146104b457806346e28a09146104e157806356b5440c146105005780635c975abb1461052d5780636b0e4f86146105415780636e15e242146105605780637879ec311461057d5780638456cb591461059c57806385572ffb146105b05780638926f54f146105cf5780638bdd6d8e146105ee5780638f20071d1461060e5780639010d07c1461063d57806391d148541461065c5780639bc53a201461067b578063a217fddf1461069a578063a3246ad3146106ad578063aa6ca808146106cc578063af58d59f146106e0578063b0f479a114610752578063bb0edba014610770578063bd9421e11461078f578063c4bffe2b146107ae578063c75eea9c146107cf578063ca15c873146107ee578063cf7401f31461080d578063d3bd04f11461082c578063d547741f1461083f578063d6111d861461085e578063db87d27814610880578063dc0bd971146108a0578063e60d6462146108c5578063e63ab1e9146108e5578063eab2c75714610905575b5f5ffd5b348015610252575f5ffd5b50610266610261366004614037565b610926565b005b348015610273575f5ffd5b50610287610282366004614052565b610996565b60405190151581526020015b60405180910390f35b3480156102a7575f5ffd5b506102666102b6366004614086565b6109cf565b3480156102c6575f5ffd5b506102da6102d53660046140d3565b610a6f565b60405161029391906140ec565b3480156102f2575f5ffd5b5061032f6040518060400160405280601d81526020017f4d756c74694c6f636b4d696e74455243373231506f6f6c20312e302e3000000081525081565b604051610293919061412e565b348015610347575f5ffd5b50610266610356366004614140565b610a79565b348015610366575f5ffd5b50610287610375366004614037565b610adf565b348015610385575f5ffd5b5061039961039436600461416a565b610b67565b604051908152602001610293565b3480156103b2575f5ffd5b506102666103c1366004614181565b610b85565b3480156103d1575f5ffd5b506102666103e03660046141c7565b610c21565b3480156103f0575f5ffd5b506102666103ff3660046140d3565b610c43565b34801561040f575f5ffd5b5061042361041e3660046140d3565b610c9c565b604051610293919061422d565b34801561043b575f5ffd5b5061039961044a36600461423f565b610de4565b34801561045a575f5ffd5b506102666104693660046142c7565b610ebb565b348015610479575f5ffd5b506102666104883660046141c7565b611022565b61039961049b366004614363565b611055565b3480156104ab575f5ffd5b50610266611077565b3480156104bf575f5ffd5b506104d36104ce3660046143cd565b611099565b6040516102939291906143fd565b3480156104ec575f5ffd5b506102876104fb366004614037565b6111a5565b34801561050b575f5ffd5b5061051f61051a3660046140d3565b6111c2565b60405161029392919061444a565b348015610538575f5ffd5b50610287611357565b34801561054c575f5ffd5b5061028761055b366004614140565b61140c565b34801561056b575f5ffd5b506032546001600160a01b03166102da565b348015610588575f5ffd5b5061026661059736600461446e565b61144e565b3480156105a7575f5ffd5b50610266611573565b3480156105bb575f5ffd5b506102666105ca3660046144b2565b611592565b3480156105da575f5ffd5b506102876105e93660046140d3565b611632565b3480156105f9575f5ffd5b506103995f516020614f195f395f51905f5281565b348015610619575f5ffd5b506102876106283660046140d3565b610162546001600160401b0391821691161490565b348015610648575f5ffd5b506102da6106573660046144e8565b6116bf565b348015610667575f5ffd5b506102876106763660046141c7565b6116eb565b348015610686575f5ffd5b506102da610695366004614508565b61171f565b3480156106a5575f5ffd5b506103995f81565b3480156106b8575f5ffd5b506104236106c736600461416a565b611768565b3480156106d7575f5ffd5b5061042361178c565b3480156106eb575f5ffd5b506106ff6106fa3660046140d3565b611880565b604051610293919081516001600160801b03908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b34801561075d575f5ffd5b50610163546001600160a01b03166102da565b34801561077b575f5ffd5b5061026661078a366004614508565b611906565b34801561079a575f5ffd5b506102876107a9366004614140565b611977565b3480156107b9575f5ffd5b506107c26119f4565b6040516102939190614574565b3480156107da575f5ffd5b506106ff6107e93660046140d3565b611b32565b3480156107f9575f5ffd5b5061039961080836600461416a565b611bb8565b348015610818575f5ffd5b5061026661082736600461459c565b611bdb565b61039961083a3660046145d5565b611c19565b34801561084a575f5ffd5b506102666108593660046141c7565b611c68565b348015610869575f5ffd5b50610872611c84565b604051610293929190614666565b34801561088b575f5ffd5b506103995f516020614f595f395f51905f5281565b3480156108ab575f5ffd5b5061016254600160401b90046001600160a01b03166102da565b3480156108d0575f5ffd5b506103995f516020614f395f395f51905f5281565b3480156108f0575f5ffd5b506103995f516020614f795f395f51905f5281565b348015610910575f5ffd5b50610919611d3c565b6040516102939190614678565b5f61093081611d4c565b603280546001600160a01b0319166001600160a01b03841690811790915561097b57603254610976905f516020614f795f395f51905f52906001600160a01b0316611d56565b505050565b6109765f516020614f795f395f51905f5283611d95565b5050565b5f6001600160e01b03198216636d7f8bbd60e11b14806109ba57506109ba82611dcb565b806109c957506109c982611e1c565b92915050565b5f516020614f595f395f51905f526109e681611d4c565b6001600160a01b038316610a0d576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0383165f81815260fd6020908152604091829020805460ff1916861515908117909155915191825233917f613ecbe5e56592771e18a638a133dc61a4488af23ac95580246a6dfa5edf240291015b60405180910390a3505050565b5f6109c982611e40565b5f516020614f195f395f51905f52610a9081611d4c565b610a9a8383611e7a565b6040516001600160a01b038316906001600160401b0385169033907f9f60ea76bb48f63c19a3d1bc23acb2a57138cbf18441efefe59a3d0c124d93ac905f90a4505050565b5f610aec61023183611fe5565b610af757505f919050565b5f610b006119f4565b80519091505f5b81811015610b5d575f6001600160a01b0316610b3c86858481518110610b2f57610b2f61468c565b602002602001015161171f565b6001600160a01b031614610b5557506001949350505050565b600101610b07565b505f949350505050565b5f5f610b71611ff9565b5f9384526020525050604090206001015490565b5f516020614f195f395f51905f52610b9c81611d4c565b83610ba68161201d565b83610bb081612044565b610bb98461201d565b610bc486868661206c565b856001600160a01b0316856001600160401b0316336001600160a01b03167feea3add3a72bfdec05437019247fe0e77d59874c7ae83510efc39677e14f9aa087604051610c1191906140ec565b60405180910390a4505050505050565b610c2a82610b67565b610c3381611d4c565b610c3d8383611d95565b50505050565b5f516020614f195f395f51905f52610c5a81611d4c565b610c6382612155565b6040516001600160401b0383169033907faf18d5efc97c08e5572a2feab86f2b1200f9ccceac5f451c0cce5d00822c5010905f90a35050565b606081610ca881612044565b6101635460405163a8d87a3b60e01b81526001600160a01b039091169063a8d87a3b90610cd9908690600401614678565b602060405180830381865afa158015610cf4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d1891906146ab565b6001600160a01b0316637437ff9f6040518163ffffffff1660e01b81526004016101a060405180830381865afa158015610d54573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d789190614784565b60e001516001600160a01b031663cdc73d516040518163ffffffff1660e01b81526004015f60405180830381865afa158015610db6573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ddd91908101906148a9565b9392505050565b6040805160c0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820152836001600160401b03811115610e2b57610e2b6146c6565b604051908082528060200260200182016040528015610e54578160200160208202803683370190505b50604051602001610e65919061496d565b60408051601f1981840301815291905260a0820152610eb085610e8781610a6f565b83604051602001610e98919061497f565b6040516020818303038152906040528660018b6121d9565b509695505050505050565b5f610ec581611d4c565b85610ed0818461238a565b610eda818661238a565b610ee3816123b4565b5f5b8181101561101757610f1c898983818110610f0257610f0261468c565b9050602002016020810190610f179190614037565b6123d4565b610f4b878783818110610f3157610f3161468c565b9050602002016020810190610f469190614037565b61201d565b888882818110610f5d57610f5d61468c565b9050602002016020810190610f729190614037565b6001600160a01b03166323b872dd30898985818110610f9357610f9361468c565b9050602002016020810190610fa89190614037565b888886818110610fba57610fba61468c565b905060200201356040518463ffffffff1660e01b8152600401610fdf939291906149ec565b5f604051808303815f87803b158015610ff6575f5ffd5b505af1158015611008573d5f5f3e3d5ffd5b50505050806001019050610ee5565b505050505050505050565b6001600160a01b038116331461104b5760405163334bd91960e11b815260040160405180910390fd5b6109768282611d56565b5f61106c878787611065886123fa565b8787612440565b979650505050505050565b5f516020614f795f395f51905f5261108e81611d4c565b611096612568565b50565b6001600160401b0383165f9081526101cb602052604090205460608184106110cf5750604080515f81526020810190915261119d565b816110da8486614a24565b11156110ed576110ea8483614a37565b92505b826001600160401b03811115611105576111056146c6565b60405190808252806020026020018201604052801561112e578160200160208202803683370190505b5090505f5b8381101561119b576001600160401b0386165f9081526101cb6020526040902061115d8287614a24565b8154811061116d5761116d61468c565b905f5260205f2001548282815181106111885761118861468c565b6020908102919091010152600101611133565b505b935093915050565b6001600160a01b03165f90815260fd602052604090205460ff1690565b6060806111ce83611632565b6111ef575050604080515f8082526020820190815281830190925292909150565b5f6111fb6102316125be565b9050806001600160401b03811115611215576112156146c6565b60405190808252806020026020018201604052801561123e578160200160208202803683370190505b509250806001600160401b03811115611259576112596146c6565b604051908082528060200260200182016040528015611282578160200160208202803683370190505b5091505f5f5b82811015611349575f61129d610231836125c7565b6001600160a01b038082165f908152610233602090815260408083206001600160401b038d16845290915290205491925016801561133f57818785815181106112e8576112e861468c565b60200260200101906001600160a01b031690816001600160a01b0316815250508086858151811061131b5761131b61468c565b6001600160a01b039092166020928302919091019091015261133c84614a4a565b93505b5050600101611288565b508084528083525050915091565b6032545f906001600160a01b031661137c5f516020614f795f395f51905f52826116eb565b801561139157506001600160a01b0381163b15155b80156113f85750806001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113d4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113f89190614a62565b8061140657506114066125d2565b91505090565b5f61141683611632565b61142157505f6109c9565b506001600160401b03919091165f90815261016660205260409020546001600160a01b0390811691161490565b5f6114576125e6565b805490915060ff600160401b82041615906001600160401b03165f8115801561147d5750825b90505f826001600160401b031660011480156114985750303b155b9050811580156114a6575080155b156114c45760405163f92ee8a960e01b815260040160405180910390fd5b84546001600160401b031916600117855583156114ed57845460ff60401b1916600160401b1785555b6114f75f89611d95565b506115018861260e565b61150a8861261f565b61151388612630565b61151e888888612641565b831561156957845460ff60401b191685556040517fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29061156090600190614678565b60405180910390a15b5050505050505050565b5f516020614f795f395f51905f5261158a81611d4c565b61109661265c565b6115a260408201602083016140d3565b6115ab816126a2565b5f6115b96040840184614a7d565b8101906115c69190614037565b90506115e16115db60408501602086016140d3565b82612741565b6115e9612782565b6115f2836127c0565b825f01357fce0ee41dd56ba56504e3cbb18167239f0ff664e41824e710d406e710e3ed0a388260405161162591906140ec565b60405180910390a2505050565b5f6116486101646001600160401b038416612957565b80156109c9575061016354604051631491520b60e31b81526001600160a01b039091169063a48a905890611680908590600401614678565b602060405180830381865afa15801561169b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109c99190614a62565b5f5f6116c9612962565b5f8581526020829052604090209091506116e390846125c7565b949350505050565b5f5f6116f5611ff9565b5f948552602090815260408086206001600160a01b03959095168652939052505090205460ff1690565b5f61172982611632565b61173457505f6109c9565b506001600160a01b039182165f908152610233602090815260408083206001600160401b0394909416835292905220541690565b60605f611773612962565b5f848152602082905260409020909150610ddd90612986565b60605f61179a610231612986565b8051909150806001600160401b038111156117b7576117b76146c6565b6040519080825280602002602001820160405280156117e0578160200160208202803683370190505b5092505f5f5b82811015611876576118108482815181106118035761180361468c565b6020026020010151610adf565b1561186e578381815181106118275761182761468c565b602002602001015185838061183b90614a4a565b94508151811061184d5761184d61468c565b60200260200101906001600160a01b031690816001600160a01b0316815250505b6001016117e6565b5080845250505090565b611888613fe6565b6001600160401b0382165f90815260986020908152604091829020825160a08101845281546001600160801b038082168352600160801b80830463ffffffff1695840195909552600160a01b90910460ff1615159482019490945260019091015480841660608301529190910490911660808201526109c990612992565b5f516020614f195f395f51905f5261191d81611d4c565b8161192781612044565b61193184846129fc565b6040516001600160a01b038516906001600160401b0385169033907f1397d60c55aea4f977e36de26ece59e6c1111bb420cc66e2d9565bc475bf82ef905f90a450505050565b5f5f61198284610c9c565b80519091505f819003611999575f925050506109c9565b5f5b818110156119e957846001600160a01b03168382815181106119bf576119bf61468c565b60200260200101516001600160a01b0316036119e157600193505050506109c9565b60010161199b565b505f95945050505050565b60605f611a02610164612986565b8051909150806001600160401b03811115611a1f57611a1f6146c6565b604051908082528060200260200182016040528015611a48578160200160208202803683370190505b5092505f5f5b82811015611876575f848281518110611a6957611a6961468c565b602090810291909101015161016354604051631491520b60e31b81529192506001600160a01b03169063a48a905890611aa6908490600401614678565b602060405180830381865afa158015611ac1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ae59190614a62565b15611b2957808684611af681614a4a565b955081518110611b0857611b0861468c565b60200260200101906001600160401b031690816001600160401b0316815250505b50600101611a4e565b611b3a613fe6565b6001600160401b0382165f90815260976020908152604091829020825160a08101845281546001600160801b038082168352600160801b80830463ffffffff1695840195909552600160a01b90910460ff1615159482019490945260019091015480841660608301529190910490911660808201526109c990612992565b5f5f611bc2612962565b5f848152602082905260409020909150610ddd906125be565b5f516020614f395f395f51905f52611bf281611d4c565b610c3d84611c0536869003860186614ad5565b611c1436869003860186614ad5565b612ab6565b5f611c5c8888888888808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152508a92508991506124409050565b98975050505050505050565b611c7182610b67565b611c7a81611d4c565b610c3d8383611d56565b606080611c8f6119f4565b8051909250806001600160401b03811115611cac57611cac6146c6565b604051908082528060200260200182016040528015611cd5578160200160208202803683370190505b5091505f5b81811015611d3657611d04848281518110611cf757611cf761468c565b6020026020010151610a6f565b838281518110611d1657611d1661468c565b6001600160a01b0390921660209283029190910190910152600101611cda565b50509091565b610162546001600160401b031690565b6110968133612b51565b5f5f611d60612962565b90505f611d6d8585612b7c565b905080156116e3575f858152602083905260409020611d8c9085612bfb565b50949350505050565b5f5f611d9f612962565b90505f611dac8585612c0f565b905080156116e3575f858152602083905260409020611d8c9085612ca4565b5f6001600160e01b031982166319167f6d60e11b1480611def5750611def82612cb8565b80611dfe5750611dfe82612cf7565b80611e0d5750611e0d82612d17565b806109c957506109c982612d37565b5f6001600160e01b031982166319c7358960e21b14806109c957506109c982612cb8565b5f611e4a82611632565b611e5557505f919050565b506001600160401b03165f90815261016660205260409020546001600160a01b031690565b611e838161201d565b610162546001600160401b0390811690831603611ebe578160405163af86032f60e01b8152600401611eb59190614678565b60405180910390fd5b61016354604051631491520b60e31b81526001600160a01b039091169063a48a905890611eef908590600401614678565b602060405180830381865afa158015611f0a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f2e9190614a62565b611f4d578160405163172ced9d60e11b8152600401611eb59190614678565b611f626101646001600160401b038416612d5b565b611f815781604051632f2c07d760e01b8152600401611eb59190614678565b6001600160401b0382165f818152610166602052604080822080546001600160a01b0319166001600160a01b038616908117909155905190929133917f8de8fd9740da5fc201a38a6085490fd6dfc07ce3a73938627eac66a5e748cefb9190a45050565b5f610ddd836001600160a01b038416612d66565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680090565b6001600160a01b038116611096576040516342bcdf7f60e11b815260040160405180910390fd5b61204d81611632565b6110965780604051631e670e4b60e01b8152600401611eb59190614678565b5f5f612077846111c2565b8051919350915015612100575f5b81518110156120fe57836001600160a01b03168282815181106120aa576120aa61468c565b60200260200101516001600160a01b0316036120f6578281815181106120d2576120d261468c565b602002602001015184604051631cfa01f360e11b8152600401611eb5929190614b42565b600101612085565b505b61210c61023186612ca4565b5050506001600160a01b039283165f908152610233602090815260408083206001600160401b039590951683529390529190912080546001600160a01b03191691909216179055565b61216a6101646001600160401b038316612d7d565b6121895780604051631e670e4b60e01b8152600401611eb59190614678565b6001600160401b0381165f818152610166602052604080822080546001600160a01b03191690555133917fb7c3517ce5cb1b2e820e49d7850f4e0e71cde55b70c0995bab3b7eafe3abc87291a350565b5f6122146040518060a001604052806060815260200160608152602001606081526020015f6001600160a01b03168152602001606081525090565b8761221e81612044565b6040805160a08101909152806122378a60c083016140ec565b60408051808303601f1901815291815290825260208083018b905281515f808252918101835292909101919061228e565b604080518082019091525f80825260208201528152602001906001900390816122685790505b508152602001856001600160a01b0316815260200161230760405180604001604052808a81526020018915158152506040805182516024820152602092830151151560448083019190915282518083039091018152606490910190915290810180516001600160e01b0316630181dcf160e41b17905290565b9052610163546040516320487ded60e01b81529193506001600160a01b0316906320487ded9061233d908c908690600401614b5c565b602060405180830381865afa158015612358573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061237c9190614c2e565b925050965096945050505050565b808214610992576040516355c5b3e360e11b81526004810183905260248101829052604401611eb5565b805f036110965760405163273e150360e21b815260040160405180910390fd5b6123dd81610adf565b6110965760405163f850ff3b60e01b815260040160405180910390fd5b6040805160018082528183019092526060916020808301908036833701905050905081815f8151811061242f5761242f61468c565b602002602001018181525050919050565b5f8461244b8161201d565b5f8560405160200161245d919061496d565b60408051601f198184030181526060830182526001600160401b038b1683526001600160a01b038c166020840152908201819052915061249c90612d88565b5f6124a78a8a61171f565b90506124b28161201d565b612548896124bf8b610a6f565b6040518060c00160405280336001600160a01b031681526020016124e1611d3c565b6001600160401b031681526020018c6001600160a01b03168152602001856001600160a01b03168152602001306001600160a01b0316815260200186815250604051602001612530919061497f565b6040516020818303038152906040528860018b612e88565b935061255b612555611d3c565b856131f7565b5050509695505050505050565b61257061329f565b5f6125796132c4565b805460ff1916815590507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516125b391906140ec565b60405180910390a150565b5f6109c9825490565b5f610ddd83836132e8565b5f5f6125dc6132c4565b5460ff1692915050565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a006109c9565b61261661330e565b61109681613333565b61262761330e565b6110968161336d565b61263861330e565b6110968161338c565b61264961330e565b612652836133ab565b61097682826133ca565b6126646133dc565b5f61266d6132c4565b805460ff1916600117815590507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125a63390565b61016254604051632cbc26bb60e01b8152608083901b600160801b600160c01b03166004820152600160401b9091046001600160a01b031690632cbc26bb90602401602060405180830381865afa1580156126ff573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127239190614a62565b1561109657604051630a75a23b60e31b815260040160405180910390fd5b61274b828261140c565b6109925760405163d5079a3560e01b81526001600160401b03831660048201526001600160a01b0382166024820152604401611eb5565b610163546001600160a01b031633146127be5761016354604051637ec1982b60e01b8152611eb5916001600160a01b0316903390600401614b42565b565b5f6127ce6060830183614a7d565b8101906127db9190614cb0565b905080602001516001600160401b03168260200160208101906127fe91906140d3565b6001600160401b03161461284d5761281c60408301602084016140d3565b6020820151604051638428f1f760e01b81526001600160401b03928316600482015291166024820152604401611eb5565b5f61285b6040840184614a7d565b8101906128689190614037565b905081608001516001600160a01b0316816001600160a01b0316146128a75760808201516040516310c4624f60e21b8152611eb5918391600401614b42565b81516128b29061201d565b60208201516128c29084356131f7565b6128cb82613402565b825f013582604001516001600160a01b0316835f01516001600160a01b03167f55e75798c6b341acacc33826c47c58fccf851dda1790809862e7299fe1874d448560a001518060200190518101906129239190614d75565b6129336040890160208a016140d3565b61293b611d3c565b60405161294a93929190614dfb565b60405180910390a4505050565b5f610ddd8383612d66565b7fc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e8237170593200090565b60605f610ddd83613420565b61299a613fe6565b6129e182606001516001600160801b0316835f01516001600160801b0316846020015163ffffffff16426129ce9190614a37565b85608001516001600160801b0316613479565b6001600160801b031682525063ffffffff4216602082015290565b6001600160a01b038083165f908152610233602090815260408083206001600160401b03861684529091529020541680612a6357604051639bc50b1760e01b81526001600160a01b03841660048201526001600160401b0383166024820152604401611eb5565b6001600160a01b0383165f908152610233602090815260408083206001600160401b0386168452909152902080546001600160a01b0319169055612aa683610adf565b61097657610c3d61023184612bfb565b612ac0825f6134a0565b6001600160401b0383165f908152609760205260409020612ae19083613561565b612aeb815f6134a0565b6001600160401b0383165f908152609860205260409020612b0c9082613561565b826001600160401b0316336001600160a01b03167f3a6cd4bdc00dc992306b6d7795432a8934d7c9fbdb85b49faad03dad43c817248484604051610a62929190614e57565b612b5b82826116eb565b61099257808260405163e2517d3f60e01b8152600401611eb5929190614e72565b5f5f612b86611ff9565b9050612b9284846116eb565b15612bf2575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a460019150506109c9565b5f9150506109c9565b5f610ddd836001600160a01b03841661367a565b5f5f612c19611ff9565b9050612c2584846116eb565b612bf2575f848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055612c5a3390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a460019150506109c9565b5f610ddd836001600160a01b038416613754565b5f6001600160e01b0319821663181f5a7760e01b1480612ce857506001600160e01b0319821663d6d62d0d60e01b145b806109c957506109c98261379b565b5f6001600160e01b03198216634d60abbd60e11b14806109c957506109c9825b5f6001600160e01b031982166320bfad4960e11b14806109c957506109c9825b5f6001600160e01b0319821663324c152b60e01b14806109c957506109c9826137eb565b5f610ddd8383613754565b5f9081526001919091016020526040902054151590565b5f610ddd838361367a565b612d906133dc565b8060200151612d9e816123d4565b8151612da981612044565b5f8360400151806020019051810190612dc29190614d75565b8051909150612dd0816123b4565b5f5b81811015612e5f5785602001516001600160a01b03166323b872dd3330868581518110612e0157612e0161468c565b60200260200101516040518463ffffffff1660e01b8152600401612e27939291906149ec565b5f604051808303815f87803b158015612e3e575f5ffd5b505af1158015612e50573d5f5f3e3d5ffd5b50505050806001019050612dd2565b50612e6f8560200151308461380f565b612e81855f0151866020015183613894565b5050505050565b5f86612e93816126a2565b612e9c8761201d565b612ea5856123b4565b612eaf86516123b4565b5f5f612ebf8a8a8a8a8a8a6121d9565b90925090505f6001600160a01b038616612ff55782341015612efd5760405163054365bb60e31b815260048101849052346024820152604401611eb5565b6101635f9054906101000a90046001600160a01b03166001600160a01b031663e861e9076040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f4e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f7291906146ab565b95508582606001906001600160a01b031690816001600160a01b031681525050856001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004015f604051808303818588803b158015612fcb575f5ffd5b505af1158015612fdd573d5f5f3e3d5ffd5b50505050508234612fee9190614a37565b905061302b565b3415613016576040516336334e4560e01b8152346004820152602401611eb5565b61302b6001600160a01b0387163330866138b6565b6101635460405163095ea7b360e01b81526001600160a01b038881169263095ea7b39261306092909116908790600401614e72565b6020604051808303815f875af115801561307c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906130a09190614a62565b50610163546040516396f4e9f960e01b81526001600160a01b03909116906396f4e9f9906130d4908e908690600401614b5c565b6020604051808303815f875af11580156130f0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131149190614c2e565b945080156131bd576040515f90339083908381818185875af1925050503d805f811461315b576040519150601f19603f3d011682016040523d82523d5f602084013e613160565b606091505b50509050806131865733826040516357b9d85960e11b8152600401611eb5929190614e72565b60405182815233907fd7dee2702d63ad89917b6a4da9981c90c4d24f8c2bdfd64c604ecae57d8d06519060200160405180910390a2505b604051859033907fb06a7d56e5736d613c3122470fadaf19fa9b76fbc2244c4ed1bab9c2c4d6213b905f90a3505050509695505050505050565b6001600160401b0382165f9081526101cc6020908152604080832084845290915290205460ff161561324e576040516342cb76b360e11b81526001600160401b038316600482015260248101829052604401611eb5565b6001600160401b039091165f8181526101cb60209081526040808320805460018181018355918552838520018690559383526101cc825280832094835293905291909120805460ff19169091179055565b6132a7611357565b6127be57604051638dfc202b60e01b815260040160405180910390fd5b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330090565b5f825f0182815481106132fd576132fd61468c565b905f5260205f200154905092915050565b613316613910565b6127be57604051631afcd79f60e31b815260040160405180910390fd5b61333b61330e565b603280546001600160a01b0319166001600160a01b0383161790556109925f516020614f795f395f51905f5282611d95565b61337561330e565b6109925f516020614f395f395f51905f5282611d95565b61339461330e565b6109925f516020614f595f395f51905f5282611d95565b6133b361330e565b6109925f516020614f195f395f51905f5282611d95565b6133d261330e565b6109928282613929565b6133e4611357565b156127be5760405163d93c066560e01b815260040160405180910390fd5b613417610f468260600151836020015161171f565b61109681613a04565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561346d57602002820191905f5260205f20905b815481526020019060010190808311613459575b50505050509050919050565b5f613497856134888486614e8b565b6134929087614a24565b613ba4565b95945050505050565b81511561351a5781602001516001600160801b031682604001516001600160801b03161015806134db575060408201516001600160801b0316155b156134fb5781604051632008344960e21b8152600401611eb59190614ea2565b80156109925760405163433fc33d60e01b815260040160405180910390fd5b60408201516001600160801b0316151580613541575060208201516001600160801b031615155b1561099257816040516335a2be7360e21b8152600401611eb59190614ea2565b81545f9061357c90600160801b900463ffffffff1642614a37565b905080156135da57600183015483546135ae916001600160801b03808216928116918591600160801b90910416613479565b83546001600160801b03919091166001600160a01b031990911617600160801b4263ffffffff16021783555b602082015183546135f7916001600160801b039081169116613ba4565b835483511515600160a01b02600164ff0000000160801b03199091166001600160801b039283161717845560208301516040808501518316600160801b0291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c199061366d908490614ea2565b60405180910390a1505050565b5f8181526001830160205260408120548015612bf2575f61369c600183614a37565b85549091505f906136af90600190614a37565b905080821461370e575f865f0182815481106136cd576136cd61468c565b905f5260205f200154905080875f0184815481106136ed576136ed61468c565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061371f5761371f614eb0565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506109c9565b5f61375f8383612d66565b61379457508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556109c9565b505f6109c9565b5f6001600160e01b031982166351fdd48d60e11b14806137cb57506001600160e01b031982166385572ffb60e01b145b806109c957506001600160e01b031982166301ffc9a760e01b1492915050565b5f6001600160e01b03198216635a05180f60e01b14806109c957506109c982613bb9565b80515f5b81811015612e8157836001600160a01b03166138488685848151811061383b5761383b61468c565b6020026020010151613bed565b6001600160a01b03161461388c57838382815181106138695761386961468c565b6020026020010151604051631cc2e71960e31b8152600401611eb5929190614e72565b600101613813565b6001600160401b0383165f908152609760205260409020610976908284613c62565b610c3d84856001600160a01b03166323b872dd8686866040516024016138de939291906149ec565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050613e73565b5f6139196125e6565b54600160401b900460ff16919050565b61393161330e565b613943816001600160401b03166123b4565b61016380546001600160a01b0319166001600160a01b03841690811790915560408051635246492f60e01b81529051635246492f916004808201926020929091908290030181865afa15801561399b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139bf91906146ab565b61016280546001600160401b039093166001600160401b03196001600160a01b0393909316600160401b02929092166001600160e01b03199093169290921717905550565b613a0c6133dc565b5f8160a00151806020019051810190613a259190614d75565b8051909150613a33816123b4565b613a40836040015161201d565b613a4d83606001516123d4565b5f5b81811015613b7d575f838281518110613a6a57613a6a61468c565b602002602001015190505f613a83866060015183613bed565b90506001600160a01b038116301480613aa05750613aa0816111a5565b15613b0f5785606001516001600160a01b03166323b872dd828860400151856040518463ffffffff1660e01b8152600401613add939291906149ec565b5f604051808303815f87803b158015613af4575f5ffd5b505af1158015613b06573d5f5f3e3d5ffd5b50505050613b73565b85606001516001600160a01b03166340c10f198760400151846040518363ffffffff1660e01b8152600401613b45929190614e72565b5f604051808303815f87803b158015613b5c575f5ffd5b505af1158015613b6e573d5f5f3e3d5ffd5b505050505b5050600101613a4f565b50613b91836060015184604001518461380f565b6109768360200151846060015183613ecb565b5f818310613bb25781610ddd565b5090919050565b5f6001600160e01b03198216637965db0b60e01b14806109c957506301ffc9a760e01b6001600160e01b03198316146109c9565b6040516331a9108f60e11b8152600481018290525f906001600160a01b03841690636352211e90602401602060405180830381865afa925050508015613c50575060408051601f3d908101601f19168201909252613c4d918101906146ab565b60015b613c5b57505f6109c9565b90506109c9565b8254600160a01b900460ff161580613c78575081155b15613c8257505050565b825460018401546001600160801b03808316929116905f90613cb190600160801b900463ffffffff1642614a37565b90508015613d1d5781831115613cda57604051634b92ca1560e11b815260040160405180910390fd5b6001860154613cfe90839085908490600160801b90046001600160801b0316613479565b865463ffffffff60801b1916600160801b4263ffffffff160217875592505b84821015613d75576001600160a01b038416613d565760405163f94ebcd160e01b81526004810183905260248101869052604401611eb5565b818585604051630d3b2b9560e11b8152600401611eb593929190614ec4565b84831015613e1257600186810154600160801b90046001600160801b0316905f908290613da29082614a37565b613dac878a614a37565b613db69190614a24565b613dc09190614ee3565b90506001600160a01b038616613df3576040516302a4f38160e31b81526004810182905260248101869052604401611eb5565b808587604051636864691d60e11b8152600401611eb593929190614ec4565b613e1c8584614a37565b86546001600160801b0319166001600160801b0382161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b5f613e876001600160a01b03841683613eed565b905080515f14158015613eab575080806020019051810190613ea99190614a62565b155b156109765782604051635274afe760e01b8152600401611eb591906140ec565b6001600160401b0383165f908152609860205260409020610976908284613c62565b6060610ddd83835f845f5f856001600160a01b03168486604051613f119190614f02565b5f6040518083038185875af1925050503d805f8114613f4b576040519150601f19603f3d011682016040523d82523d5f602084013e613f50565b606091505b5091509150613f60868383613f6a565b9695505050505050565b606082613f7f57613f7a82613fbd565b610ddd565b8151158015613f9657506001600160a01b0384163b155b15613fb65783604051639996b31560e01b8152600401611eb591906140ec565b5080610ddd565b805115613fcd5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6040805160a0810182525f8082526020820181905291810182905260608101829052608081019190915290565b6001600160a01b0381168114611096575f5ffd5b803561403281614013565b919050565b5f60208284031215614047575f5ffd5b8135610ddd81614013565b5f60208284031215614062575f5ffd5b81356001600160e01b031981168114610ddd575f5ffd5b8015158114611096575f5ffd5b5f5f60408385031215614097575f5ffd5b82356140a281614013565b915060208301356140b281614079565b809150509250929050565b80356001600160401b0381168114614032575f5ffd5b5f602082840312156140e3575f5ffd5b610ddd826140bd565b6001600160a01b0391909116815260200190565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610ddd6020830184614100565b5f5f60408385031215614151575f5ffd5b61415a836140bd565b915060208301356140b281614013565b5f6020828403121561417a575f5ffd5b5035919050565b5f5f5f60608486031215614193575f5ffd5b833561419e81614013565b92506141ac602085016140bd565b915060408401356141bc81614013565b809150509250925092565b5f5f604083850312156141d8575f5ffd5b8235915060208301356140b281614013565b5f8151808452602084019350602083015f5b828110156142235781516001600160a01b03168652602095860195909101906001016141fc565b5093949350505050565b602081525f610ddd60208301846141ea565b5f5f5f5f60808587031215614252575f5ffd5b843561425d81614013565b935061426b602086016140bd565b93969395505050506040820135916060013590565b5f5f83601f840112614290575f5ffd5b5081356001600160401b038111156142a6575f5ffd5b6020830191508360208260051b85010111156142c0575f5ffd5b9250929050565b5f5f5f5f5f5f606087890312156142dc575f5ffd5b86356001600160401b038111156142f1575f5ffd5b6142fd89828a01614280565b90975095505060208701356001600160401b0381111561431b575f5ffd5b61432789828a01614280565b90955093505060408701356001600160401b03811115614345575f5ffd5b61435189828a01614280565b979a9699509497509295939492505050565b5f5f5f5f5f5f60c08789031215614378575f5ffd5b863561438381614013565b9550614391602088016140bd565b945060408701356143a181614013565b93506060870135925060808701356143b881614013565b9598949750929591949360a090920135925050565b5f5f5f606084860312156143df575f5ffd5b6143e8846140bd565b95602085013595506040909401359392505050565b5f60408201848352604060208401528084518083526060850191506020860192505f5b8181101561443e578351835260209384019390920191600101614420565b50909695505050505050565b604081525f61445c60408301856141ea565b828103602084015261349781856141ea565b5f5f5f60608486031215614480575f5ffd5b833561448b81614013565b9250602084013561449b81614013565b91506144a9604085016140bd565b90509250925092565b5f602082840312156144c2575f5ffd5b81356001600160401b038111156144d7575f5ffd5b820160a08185031215610ddd575f5ffd5b5f5f604083850312156144f9575f5ffd5b50508035926020909101359150565b5f5f60408385031215614519575f5ffd5b823561452481614013565b9150614532602084016140bd565b90509250929050565b5f8151808452602084019350602083015f5b828110156142235781516001600160401b031686526020958601959091019060010161454d565b602081525f610ddd602083018461453b565b5f60608284031215614596575f5ffd5b50919050565b5f5f5f60e084860312156145ae575f5ffd5b6145b7846140bd565b92506145c68560208601614586565b91506144a98560808601614586565b5f5f5f5f5f5f5f60c0888a0312156145eb575f5ffd5b87356145f681614013565b9650614604602089016140bd565b9550604088013561461481614013565b945060608801356001600160401b0381111561462e575f5ffd5b61463a8a828b01614280565b909550935050608088013561464e81614013565b96999598509396929591949193505060a09091013590565b604081525f61445c604083018561453b565b6001600160401b0391909116815260200190565b634e487b7160e01b5f52603260045260245ffd5b805161403281614013565b5f602082840312156146bb575f5ffd5b8151610ddd81614013565b634e487b7160e01b5f52604160045260245ffd5b6040516101a081016001600160401b03811182821017156146fd576146fd6146c6565b60405290565b60405160c081016001600160401b03811182821017156146fd576146fd6146c6565b604051601f8201601f191681016001600160401b038111828210171561474d5761474d6146c6565b604052919050565b805161ffff81168114614032575f5ffd5b805163ffffffff81168114614032575f5ffd5b805161403281614079565b5f6101a0828403128015614796575f5ffd5b5061479f6146da565b6147a8836146a0565b81526147b660208401614755565b60208201526147c760408401614766565b60408201526147d860608401614755565b60608201526147e960808401614766565b60808201526147fa60a08401614755565b60a082015261480b60c08401614755565b60c082015261481c60e084016146a0565b60e082015261482e6101008401614766565b6101008201526148416101208401614766565b6101208201526148546101408401614755565b6101408201526148676101608401614766565b61016082015261487a6101808401614779565b6101808201529392505050565b5f6001600160401b0382111561489f5761489f6146c6565b5060051b60200190565b5f602082840312156148b9575f5ffd5b81516001600160401b038111156148ce575f5ffd5b8201601f810184136148de575f5ffd5b80516148f16148ec82614887565b614725565b8082825260208201915060208360051b850101925086831115614912575f5ffd5b6020840193505b82841015613f6057835161492c81614013565b825260209384019390910190614919565b5f8151808452602084019350602083015f5b8281101561422357815186526020958601959091019060010161494f565b602081525f610ddd602083018461493d565b602080825282516001600160a01b0390811683830152908301516001600160401b0316604080840191909152830151811660608084019190915283015181166080808401919091528301511660a08083019190915282015160c0808301525f906116e360e0840182614100565b6001600160a01b039384168152919092166020820152604081019190915260600190565b634e487b7160e01b5f52601160045260245ffd5b808201808211156109c9576109c9614a10565b818103818111156109c9576109c9614a10565b5f60018201614a5b57614a5b614a10565b5060010190565b5f60208284031215614a72575f5ffd5b8151610ddd81614079565b5f5f8335601e19843603018112614a92575f5ffd5b8301803591506001600160401b03821115614aab575f5ffd5b6020019150368190038213156142c0575f5ffd5b80356001600160801b0381168114614032575f5ffd5b5f6060828403128015614ae6575f5ffd5b50604051606081016001600160401b0381118282101715614b0957614b096146c6565b6040528235614b1781614079565b8152614b2560208401614abf565b6020820152614b3660408401614abf565b60408201529392505050565b6001600160a01b0392831681529116602082015260400190565b60018060401b0383168152604060208201525f825160a06040840152614b8560e0840182614100565b90506020840151603f19848303016060850152614ba28282614100565b6040860151858203603f190160808701528051808352602091820194505f93509101905b80831015614bfd57835180516001600160a01b03168352602090810151818401529093019260019290920191604090910190614bc6565b5060608601516001600160a01b031660a08601526080860151858203603f190160c0870152925061106c8184614100565b5f60208284031215614c3e575f5ffd5b5051919050565b5f82601f830112614c54575f5ffd5b81356001600160401b03811115614c6d57614c6d6146c6565b614c80601f8201601f1916602001614725565b818152846020838601011115614c94575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60208284031215614cc0575f5ffd5b81356001600160401b03811115614cd5575f5ffd5b820160c08185031215614ce6575f5ffd5b614cee614703565b8135614cf981614013565b8152614d07602083016140bd565b60208201526040820135614d1a81614013565b60408201526060820135614d2d81614013565b6060820152614d3e60808301614027565b608082015260a08201356001600160401b03811115614d5b575f5ffd5b614d6786828501614c45565b60a083015250949350505050565b5f60208284031215614d85575f5ffd5b81516001600160401b03811115614d9a575f5ffd5b8201601f81018413614daa575f5ffd5b8051614db86148ec82614887565b8082825260208201915060208360051b850101925086831115614dd9575f5ffd5b6020840193505b82841015613f60578351825260209384019390910190614de0565b606081525f614e0d606083018661493d565b6001600160401b0394851660208401529290931660409091015292915050565b8051151582526020808201516001600160801b039081169184019190915260409182015116910152565b60c08101614e658285614e2d565b610ddd6060830184614e2d565b6001600160a01b03929092168252602082015260400190565b80820281158282048414176109c9576109c9614a10565b606081016109c98284614e2d565b634e487b7160e01b5f52603160045260245ffd5b92835260208301919091526001600160a01b0316604082015260600190565b5f82614efd57634e487b7160e01b5f52601260045260245ffd5b500490565b5f82518060208501845e5f92019182525091905056fe9562977e123fbe4558c4ac6a21f5c0a7f5ee8c1bd1bb59ec24cd079022975cb815975e67e85433b86162c65eeaf7d19d2b619671751d1f6d4d320dc195d465db1688c00bd4b3d5d2661432cff443a73d99517e416fd98c1425d800f7b6b0b9e965d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862aa2646970667358221220bba0137ca3101440e2b76765b14e4154ddbde848a7797d09aa47ff6d4820a23064736f6c634300081d0033
Deployed Bytecode Sourcemap
473:4391:48:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1932:306:28;;;;;;;;;;-1:-1:-1;1932:306:28;;;;;:::i;:::-;;:::i;:::-;;2564:366:48;;;;;;;;;;-1:-1:-1;2564:366:48;;;;;:::i;:::-;;:::i;:::-;;;997:14:49;;990:22;972:41;;960:2;945:18;2564:366:48;;;;;;;;1281:322:30;;;;;;;;;;-1:-1:-1;1281:322:30;;;;;:::i;:::-;;:::i;3158:153:46:-;;;;;;;;;;-1:-1:-1;3158:153:46;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;576:80:48:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;1721:252:46:-;;;;;;;;;;-1:-1:-1;1721:252:46;;;;;:::i;:::-;;:::i;2738:607:45:-;;;;;;;;;;-1:-1:-1;2738:607:45;;;;;:::i;:::-;;:::i;4759:191:12:-;;;;;;;;;;-1:-1:-1;4759:191:12;;;;;:::i;:::-;;:::i;:::-;;;3436:25:49;;;3424:2;3409:18;4759:191:12;3290:177:49;2293:434:46;;;;;;;;;;-1:-1:-1;2293:434:46;;;;;:::i;:::-;;:::i;5246:136:12:-;;;;;;;;;;-1:-1:-1;5246:136:12;;;;;:::i;:::-;;:::i;2025:216:46:-;;;;;;;;;;-1:-1:-1;2025:216:46;;;;;:::i;:::-;;:::i;4041:300:27:-;;;;;;;;;;-1:-1:-1;4041:300:27;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;1170:591:47:-;;;;;;;;;;-1:-1:-1;1170:591:47;;;;;:::i;:::-;;:::i;1132:589:48:-;;;;;;;;;;-1:-1:-1;1132:589:48;;;;;:::i;:::-;;:::i;6348:245:12:-;;;;;;;;;;-1:-1:-1;6348:245:12;;;;;:::i;:::-;;:::i;1787:353:48:-;;;;;;:::i;:::-;;:::i;1416:77:28:-;;;;;;;;;;;;;:::i;3842:525:46:-;;;;;;;;;;-1:-1:-1;3842:525:46;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;1883:133:30:-;;;;;;;;;;-1:-1:-1;1883:133:30;;;;;:::i;:::-;;:::i;1156:958:45:-;;;;;;;;;;-1:-1:-1;1156:958:45;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;2244:275:28:-;;;;;;;;;;;;;:::i;4887:236:27:-;;;;;;;;;;-1:-1:-1;4887:236:27;;;;;:::i;:::-;;:::i;1763:110:28:-;;;;;;;;;;-1:-1:-1;1852:14:28;;-1:-1:-1;;;;;1852:14:28;1763:110;;722:344:48;;;;;;;;;;-1:-1:-1;722:344:48;;;;;:::i;:::-;;:::i;1284:73:28:-;;;;;;;;;;;;;:::i;3095:402:27:-;;;;;;;;;;-1:-1:-1;3095:402:27;;;;;:::i;:::-;;:::i;4615:211::-;;;;;;;;;;-1:-1:-1;4615:211:27;;;;;:::i;:::-;;:::i;643:82:46:-;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;643:82:46;;4402:152:27;;;;;;;;;;-1:-1:-1;4402:152:27;;;;;:::i;:::-;4525:22;;-1:-1:-1;;;;;4501:46:27;;;4525:22;;4501:46;;4402:152;2492:233:13;;;;;;;;;;-1:-1:-1;2492:233:13;;;;;:::i;:::-;;:::i;3732:207:12:-;;;;;;;;;;-1:-1:-1;3732:207:12;;;;;:::i;:::-;;:::i;3402:256:45:-;;;;;;;;;;-1:-1:-1;3402:256:45;;;;;:::i;:::-;;:::i;2317:49:12:-;;;;;;;;;;-1:-1:-1;2317:49:12;2362:4;2317:49;;3658:227:13;;;;;;;;;;-1:-1:-1;3658:227:13;;;;;:::i;:::-;;:::i;2171:515:45:-;;;;;;;;;;;;;:::i;2346:247:29:-;;;;;;;;;;-1:-1:-1;2346:247:29;;;;;:::i;:::-;;:::i;:::-;;;;;;11443:13:49;;-1:-1:-1;;;;;11439:39:49;;;11421:58;;11539:4;11527:17;;;11521:24;11547:10;11517:41;11495:20;;;11488:71;11629:4;11617:17;;;11611:24;11604:32;11597:40;11575:20;;;11568:70;11698:4;11686:17;;;11680:24;11676:50;;11654:20;;;11647:80;11466:3;11775:17;;;11769:24;11765:50;11743:20;;;11736:80;;;;11408:3;11393:19;;11216:606;6104:104:27;;;;;;;;;;-1:-1:-1;6193:8:27;;-1:-1:-1;;;;;6193:8:27;6104:104;;2779:327:46;;;;;;;;;;-1:-1:-1;2779:327:46;;;;;:::i;:::-;;:::i;3558:422:27:-;;;;;;;;;;-1:-1:-1;3558:422:27;;;;;:::i;:::-;;:::i;5184:667::-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;2037:249:29:-;;;;;;;;;;-1:-1:-1;2037:249:29;;;;;:::i;:::-;;:::i;2893:222:13:-;;;;;;;;;;-1:-1:-1;2893:222:13;;;;;:::i;:::-;;:::i;1460:305:29:-;;;;;;;;;;-1:-1:-1;1460:305:29;;;;;:::i;:::-;;:::i;2206:352:48:-;;;;;;:::i;:::-;;:::i;5662:138:12:-;;;;;;;;;;-1:-1:-1;5662:138:12;;;;;:::i;:::-;;:::i;3363:427:46:-;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;474:92:30:-;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;474:92:30;;6269:95:27;;;;;;;;;;-1:-1:-1;6347:10:27;;-1:-1:-1;;;6347:10:27;;-1:-1:-1;;;;;6347:10:27;6269:95;;605:74:29;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;605:74:29;;646:62:28;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;646:62:28;;5912:131:27;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;1932:306:28:-;2362:4:12;3191:16;2362:4;3191:10;:16::i;:::-;2027:14:28::1;:29:::0;;-1:-1:-1;;;;;;2027:29:28::1;-1:-1:-1::0;;;;;2027:29:28;::::1;::::0;;::::1;::::0;;;2067:117:::1;;2138:14;::::0;2113:40:::1;::::0;-1:-1:-1;;;;;;;;;;;684:24:28;-1:-1:-1;;;;;2138:14:28::1;2113:11;:40::i;:::-;;1932:306:::0;;:::o;2067:117::-:1;2194:37;-1:-1:-1::0;;;;;;;;;;;2218:12:28::1;2194:10;:37::i;3217:1:12:-;1932:306:28::0;;:::o;2564:366:48:-;2725:4;-1:-1:-1;;;;;;2752:57:48;;-1:-1:-1;;;2752:57:48;;:122;;;2825:49;2862:11;2825:36;:49::i;:::-;2752:171;;;;2878:45;2911:11;2878:32;:45::i;:::-;2745:178;2564:366;-1:-1:-1;;2564:366:48:o;1281:322:30:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;-1:-1:-1;;;;;1406:27:30;::::1;1402:69;;1442:29;;-1:-1:-1::0;;;1442:29:30::1;;;;;;;;;;;1402:69;-1:-1:-1::0;;;;;1481:30:30;::::1;;::::0;;;:15:::1;:30;::::0;;;;;;;;:42;;-1:-1:-1;;1481:42:30::1;::::0;::::1;;::::0;;::::1;::::0;;;1538:58;;972:41:49;;;1559:10:30::1;::::0;1538:58:::1;::::0;945:18:49;1538:58:30::1;;;;;;;;1281:322:::0;;;:::o;3158:153:46:-;3230:18;3267:37;3284:19;3267:16;:37::i;1721:252::-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;1843:48:46::1;1859:19;1880:10;1843:15;:48::i;:::-;1906:60;::::0;-1:-1:-1;;;;;1906:60:46;::::1;::::0;-1:-1:-1;;;;;1906:60:46;::::1;::::0;1922:10:::1;::::0;1906:60:::1;::::0;;;::::1;1721:252:::0;;;:::o;2738:607:45:-;2822:8;2903:34;:13;2926:10;2903:22;:34::i;:::-;2898:53;;-1:-1:-1;2946:5:45;;2738:607;-1:-1:-1;2738:607:45:o;2898:53::-;3027:31;3061:20;:18;:20::i;:::-;3112:22;;3027:54;;-1:-1:-1;3091:18:45;3145:171;3165:10;3161:1;:14;3145:171;;;3258:1;-1:-1:-1;;;;;3200:60:45;:46;3215:10;3227:15;3243:1;3227:18;;;;;;;;:::i;:::-;;;;;;;3200:14;:46::i;:::-;-1:-1:-1;;;;;3200:60:45;;3196:110;;-1:-1:-1;3287:4:45;;2738:607;-1:-1:-1;;;;2738:607:45:o;3196:110::-;3177:3;;3145:171;;;-1:-1:-1;3333:5:45;;2738:607;-1:-1:-1;;;;2738:607:45:o;4759:191:12:-;4824:7;4843:30;4876:26;:24;:26::i;:::-;4919:8;:14;;;;;-1:-1:-1;;4919:14:12;;;:24;;;;4759:191::o;2293:434:46:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;2459:10:46::1;2325:21:27;2341:4;2325:15;:21::i;:::-;2496:19:46::2;2092:41:27;2113:19;2092:20;:41::i;:::-;2531:28:46::3;2547:11;2531:15;:28::i;:::-;2569:61;2585:10;2597:19;2618:11;2569:15;:61::i;:::-;2696:10;-1:-1:-1::0;;;;;2645:75:46::3;2675:19;-1:-1:-1::0;;;;;2645:75:46::3;2663:10;-1:-1:-1::0;;;;;2645:75:46::3;;2708:11;2645:75;;;;;;:::i;:::-;;;;;;;;2356:1:27::2;3217::12::1;2293:434:46::0;;;;:::o;5246:136:12:-;5320:18;5333:4;5320:12;:18::i;:::-;3191:16;3202:4;3191:10;:16::i;:::-;5350:25:::1;5361:4;5367:7;5350:10;:25::i;:::-;;5246:136:::0;;;:::o;2025:216:46:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;2130:39:46::1;2149:19;2130:18;:39::i;:::-;2184:50;::::0;-1:-1:-1;;;;;2184:50:46;::::1;::::0;2202:10:::1;::::0;2184:50:::1;::::0;;;::::1;2025:216:::0;;:::o;4041:300:27:-;4182:26;4144:19;2092:41;2113:19;2092:20;:41::i;:::-;4246:8:::1;::::0;:39:::1;::::0;-1:-1:-1;;;4246:39:27;;-1:-1:-1;;;;;4246:8:27;;::::1;::::0;:18:::1;::::0;:39:::1;::::0;4265:19;;4246:39:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;4231:72:27::1;;:74;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:88;;;-1:-1:-1::0;;;;;4231:101:27::1;;:103;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;4231:103:27::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;4224:110:::0;4041:300;-1:-1:-1;;;4041:300:27:o;1170:591:47:-;-1:-1:-1;;;;;;;;1322:11:47;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1438:10:47;-1:-1:-1;;;;;1424:25:47;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1424:25:47;;1413:37;;;;;;;;:::i;:::-;;;;-1:-1:-1;;1413:37:47;;;;;;;;;1390:20;;;:60;1470:284;1521:19;1564:34;1521:19;1564:13;:34::i;:::-;1629:5;1618:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;1659:8;1707:4;1735:8;1470:15;:284::i;:::-;-1:-1:-1;1461:293:47;1170:591;-1:-1:-1;;;;;;1170:591:47:o;1132:589:48:-;2362:4:12;3191:16;2362:4;3191:10;:16::i;:::-;1328:11:48;1356:43:::1;1328:11:::0;1388:3;1356:19:::1;:43::i;:::-;1409;1429:10:::0;1441:3;1409:19:::1;:43::i;:::-;1462:27;1478:10;1462:15;:27::i;:::-;1505:9;1500:215;1520:10;1516:1;:14;1500:215;;;1551:34;1570:11;;1582:1;1570:14;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;1551:18;:34::i;:::-;1599:23;1615:3;;1619:1;1615:6;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;1599:15;:23::i;:::-;1645:11;;1657:1;1645:14;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;1637:36:48::1;;1682:4;1689:3;;1693:1;1689:6;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;1697:3;;1701:1;1697:6;;;;;;;:::i;:::-;;;;;;;1637:67;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1532:3;;;;;1500:215;;;;1297:424;1132:589:::0;;;;;;;:::o;6348:245:12:-;-1:-1:-1;;;;;6441:34:12;;966:10:15;6441:34:12;6437:102;;6498:30;;-1:-1:-1;;;6498:30:12;;;;;;;;;;;6437:102;6549:37;6561:4;6567:18;6549:11;:37::i;1787:353:48:-;1998:17;2034:99;2054:10;2066:19;2087:2;2091:21;2109:2;2091:17;:21::i;:::-;2114:8;2124;2034:19;:99::i;:::-;2027:106;1787:353;-1:-1:-1;;;;;;;1787:353:48:o;1416:77:28:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;1476:10:28::1;:8;:10::i;:::-;1416:77:::0;:::o;3842:525:46:-;-1:-1:-1;;;;;4033:27:46;;3965:14;4033:27;;;:12;:27;;;;;:34;3981:27;4082:16;;;4078:55;;-1:-1:-1;4116:16:46;;;4130:1;4116:16;;;;;;;;4100:33;;4078:55;4164:6;4147:14;4156:5;4147:6;:14;:::i;:::-;:23;4143:52;;;4180:15;4189:6;4180;:15;:::i;:::-;4172:23;;4143:52;4233:5;-1:-1:-1;;;;;4219:20:46;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4219:20:46;;4206:33;;4254:9;4249:112;4269:5;4265:1;:9;4249:112;;;-1:-1:-1;;;;;4311:27:46;;;;;;:12;:27;;;;;4339:10;4348:1;4339:6;:10;:::i;:::-;4311:39;;;;;;;;:::i;:::-;;;;;;;;;4295:10;4306:1;4295:13;;;;;;;;:::i;:::-;;;;;;;;;;:55;4276:3;;4249:112;;;;3842:525;;;;;;;:::o;1883:133:30:-;-1:-1:-1;;;;;1979:30:30;1952:8;1979:30;;;:15;:30;;;;;;;;;1883:133::o;1156:958:45:-;1265:28;1295:29;1345:37;1362:19;1345:16;:37::i;:::-;1340:87;;-1:-1:-1;;1392:16:45;;;1406:1;1392:16;;;;;;1410;;;;;;;;;1392;;;-1:-1:-1;1156:958:45:o;1340:87::-;1438:18;1459:22;:13;:20;:22::i;:::-;1438:43;;1519:10;-1:-1:-1;;;;;1505:25:45;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1505:25:45;;1491:39;;1569:10;-1:-1:-1;;;;;1555:25:45;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1555:25:45;;1540:40;;1590:13;1619:9;1614:369;1634:10;1630:1;:14;1614:369;;;1665:18;1686:19;:13;1703:1;1686:16;:19::i;:::-;-1:-1:-1;;;;;1741:26:45;;;1719:19;1741:26;;;:14;:26;;;;;;;;-1:-1:-1;;;;;1741:47:45;;;;;;;;;;1665:40;;-1:-1:-1;1741:47:45;1806:25;;1802:171;;1872:10;1851:11;1863:5;1851:18;;;;;;;;:::i;:::-;;;;;;:31;-1:-1:-1;;;;;1851:31:45;;;-1:-1:-1;;;;;1851:31:45;;;;;1922:11;1900:12;1913:5;1900:19;;;;;;;;:::i;:::-;-1:-1:-1;;;;;1900:33:45;;;:19;;;;;;;;;;;:33;1951:7;;;:::i;:::-;;;1802:171;-1:-1:-1;;1646:3:45;;1614:369;;;;2052:5;2039:11;2032:26;2092:5;2078:12;2071:27;2018:90;;1156:958;;;:::o;2244:275:28:-;2339:14;;2300:4;;-1:-1:-1;;;;;2339:14:28;2371:34;-1:-1:-1;;;;;;;;;;;2339:14:28;2371:7;:34::i;:::-;:60;;;;-1:-1:-1;;;;;;2604:18:28;;;:22;;2409;2371:96;;;;;2445:12;-1:-1:-1;;;;;2435:30:28;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2370:142;;;;2484:28;:26;:28::i;:::-;2363:149;;;2244:275;:::o;4887:236:27:-;4977:8;5002:37;5019:19;5002:16;:37::i;:::-;4997:56;;-1:-1:-1;5048:5:27;5041:12;;4997:56;-1:-1:-1;;;;;;5070:36:27;;;;;;;;:15;:36;;;;;;-1:-1:-1;;;;;5070:36:27;;;:46;;;;4887:236::o;722:344:48:-;4158:30:14;4191:26;:24;:26::i;:::-;4302:15;;4158:59;;-1:-1:-1;4302:15:14;-1:-1:-1;;;4302:15:14;;;4301:16;;-1:-1:-1;;;;;4348:14:14;4279:19;4724:16;;:34;;;;;4744:14;4724:34;4704:54;;4768:17;4788:11;-1:-1:-1;;;;;4788:16:14;4803:1;4788:16;:50;;;;-1:-1:-1;4816:4:14;4808:25;:30;4788:50;4768:70;;4854:12;4853:13;:30;;;;;4871:12;4870:13;4853:30;4849:91;;;4906:23;;-1:-1:-1;;;4906:23:14;;;;;;;;;;;4849:91;4949:18;;-1:-1:-1;;;;;;4949:18:14;4966:1;4949:18;;;4977:67;;;;5011:22;;-1:-1:-1;;;;5011:22:14;-1:-1:-1;;;5011:22:14;;;4977:67;833:37:48::1;2362:4:12;864:5:48::0;833:10:::1;:37::i;:::-;;880:30;904:5;880:23;:30::i;:::-;920:31;945:5;920:24;:31::i;:::-;961:35;990:5;961:28;:35::i;:::-;1006:53;1023:5;1030:6;1038:20;1006:16;:53::i;:::-;5068:14:14::0;5064:101;;;5098:23;;-1:-1:-1;;;;5098:23:14;;;5140:14;;;;;;5098:23;;5140:14;:::i;:::-;;;;;;;;5064:101;4092:1079;;;;;722:344:48;;;:::o;1284:73:28:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;1342:8:28::1;:6;:8::i;3095:402:27:-:0;3208:27;;;;;;;;:::i;:::-;2427:38;2445:19;2427:17;:38::i;:::-;3251:14:::1;3279;;::::0;::::1;:7:::0;:14:::1;:::i;:::-;3268:37;;;;;;;:::i;:::-;3251:54:::0;-1:-1:-1;3316:58:27::1;3338:27;::::0;;;::::1;::::0;::::1;;:::i;:::-;3367:6;3316:21;:58::i;:::-;3384:16;:14;:16::i;:::-;3411:21;3424:7;3411:12;:21::i;:::-;3472:7;:17;;;3448:42;3464:6;3448:42;;;;;;:::i;:::-;;;;;;;;3241:256;3095:402:::0;;:::o;4615:211::-;4690:8;4717:52;:22;-1:-1:-1;;;;;4717:52:27;;:31;:52::i;:::-;:102;;;;-1:-1:-1;4773:8:27;;:46;;-1:-1:-1;;;4773:46:27;;-1:-1:-1;;;;;4773:8:27;;;;:25;;:46;;4799:19;;4773:46;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;2492:233:13:-;2573:7;2592:40;2635:36;:34;:36::i;:::-;2688:14;:20;;;;;;;;;;2592:79;;-1:-1:-1;2688:30:13;;2712:5;2688:23;:30::i;:::-;2681:37;2492:233;-1:-1:-1;;;;2492:233:13:o;3732:207:12:-;3809:4;3825:30;3858:26;:24;:26::i;:::-;3901:8;:14;;;;;;;;;;;-1:-1:-1;;;;;3901:31:12;;;;;;;;;-1:-1:-1;;3901:31:12;;;;;;3732:207::o;3402:256:45:-;3495:19;3531:37;3548:19;3531:16;:37::i;:::-;3526:61;;-1:-1:-1;3585:1:45;3570:17;;3526:61;-1:-1:-1;;;;;;3604:26:45;;;;;;;:14;:26;;;;;;;;-1:-1:-1;;;;;3604:47:45;;;;;;;;;;;;;3402:256::o;3658:227:13:-;3725:16;3753:40;3796:36;:34;:36::i;:::-;3849:14;:20;;;;;;;;;;3753:79;;-1:-1:-1;3849:29:13;;:27;:29::i;2171:515:45:-;2213:28;2253:25;2281:22;:13;:20;:22::i;:::-;2334:15;;2253:50;;-1:-1:-1;2334:15:45;-1:-1:-1;;;;;2374:25:45;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2374:25:45;;2360:39;;2409:13;2437:9;2432:163;2452:10;2448:1;:14;2432:163;;;2487:29;2504:8;2513:1;2504:11;;;;;;;;:::i;:::-;;;;;;;2487:16;:29::i;:::-;2483:102;;;2559:8;2568:1;2559:11;;;;;;;;:::i;:::-;;;;;;;2536;2548:7;;;;;:::i;:::-;;;2536:20;;;;;;;;:::i;:::-;;;;;;:34;-1:-1:-1;;;;;2536:34:45;;;-1:-1:-1;;;;;2536:34:45;;;;;2483:102;2464:3;;2432:163;;;;2664:5;2651:11;2644:26;2630:50;;;2171:515;:::o;2346:247:29:-;2464:36;;:::i;:::-;-1:-1:-1;;;;;2523:36:29;;;;;;:15;:36;;;;;;;;;:61;;;;;;;;;-1:-1:-1;;;;;2523:61:29;;;;;-1:-1:-1;;;2523:61:29;;;;;;;;;;;;-1:-1:-1;;;2523:61:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:63;;:61;:63::i;2779:327:46:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;2935:19:46::1;2092:41:27;2113:19;2092:20;:41::i;:::-;2970:50:46::2;2988:10;3000:19;2970:17;:50::i;:::-;3035:64;::::0;-1:-1:-1;;;;;3035:64:46;::::2;::::0;-1:-1:-1;;;;;3035:64:46;::::2;::::0;3055:10:::2;::::0;3035:64:::2;::::0;;;::::2;3217:1:12::1;2779:327:46::0;;;:::o;3558:422:27:-;3656:8;3676:26;3705:33;3718:19;3705:12;:33::i;:::-;3772:16;;3676:62;;-1:-1:-1;3748:21:27;3802:18;;;3798:36;;3829:5;3822:12;;;;;;3798:36;3850:9;3845:106;3865:13;3861:1;:17;3845:106;;;3919:8;-1:-1:-1;;;;;3903:24:27;:9;3913:1;3903:12;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;3903:24:27;;3899:41;;3936:4;3929:11;;;;;;;3899:41;3880:3;;3845:106;;;-1:-1:-1;3968:5:27;;3558:422;-1:-1:-1;;;;;3558:422:27:o;5184:667::-;5235:36;5283:23;5309:31;:22;:29;:31::i;:::-;5367:13;;5283:57;;-1:-1:-1;5367:13:27;-1:-1:-1;;;;;5413:20:27;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;5413:20:27;;5390:43;;5443:13;5472:9;5467:211;5487:6;5483:1;:10;5467:211;;;5514:12;5536:6;5543:1;5536:9;;;;;;;;:::i;:::-;;;;;;;;;;;5564:8;;:32;;-1:-1:-1;;;5564:32:27;;5536:9;;-1:-1:-1;;;;;;5564:8:27;;:25;;:32;;5536:9;;5564:32;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5560:108;;;5648:5;5616:20;5637:7;;;;:::i;:::-;;;5616:29;;;;;;;;:::i;:::-;;;;;;:37;-1:-1:-1;;;;;5616:37:27;;;-1:-1:-1;;;;;5616:37:27;;;;;5560:108;-1:-1:-1;5495:3:27;;5467:211;;2037:249:29;2156:36;;:::i;:::-;-1:-1:-1;;;;;2215:37:29;;;;;;:16;:37;;;;;;;;;:62;;;;;;;;;-1:-1:-1;;;;;2215:62:29;;;;;-1:-1:-1;;;2215:62:29;;;;;;;;;;;;-1:-1:-1;;;2215:62:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:64;;:62;:64::i;2893:222:13:-;2964:7;2983:40;3026:36;:34;:36::i;:::-;3079:14;:20;;;;;;;;;;2983:79;;-1:-1:-1;3079:29:13;;:27;:29::i;1460:305:29:-;-1:-1:-1;;;;;;;;;;;3191:16:12;3202:4;3191:10;:16::i;:::-;1687:71:29::1;1707:19:::0;1687:71:::1;;::::0;;::::1;::::0;::::1;1728:14:::0;1687:71:::1;:::i;:::-;;;::::0;;::::1;::::0;::::1;1744:13:::0;1687:71:::1;:::i;:::-;:19;:71::i;2206:352:48:-:0;2434:17;2470:81;2490:10;2502:19;2523:2;2527:3;;2470:81;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2532:8:48;;-1:-1:-1;2542:8:48;;-1:-1:-1;2470:19:48;;-1:-1:-1;2470:81:48:i;:::-;2463:88;2206:352;-1:-1:-1;;;;;;;;2206:352:48:o;5662:138:12:-;5737:18;5750:4;5737:12;:18::i;:::-;3191:16;3202:4;3191:10;:16::i;:::-;5767:26:::1;5779:4;5785:7;5767:11;:26::i;3363:427:46:-:0;3436:36;3474:28;3541:20;:18;:20::i;:::-;3588:27;;3518:43;;-1:-1:-1;3588:27:46;-1:-1:-1;;;;;3639:21:46;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3639:21:46;;3625:35;;3676:9;3671:113;3691:6;3687:1;:10;3671:113;;;3735:38;3749:20;3770:1;3749:23;;;;;;;;:::i;:::-;;;;;;;3735:13;:38::i;:::-;3718:11;3730:1;3718:14;;;;;;;;:::i;:::-;-1:-1:-1;;;;;3718:55:46;;;:14;;;;;;;;;;;:55;3699:3;;3671:113;;;;3508:282;3363:427;;:::o;5912:131:27:-;6014:22;;-1:-1:-1;;;;;6014:22:27;;5912:131::o;4148:103:12:-;4214:30;4225:4;966:10:15;4214::12;:30::i;4438:353:13:-;4525:4;4541:40;4584:36;:34;:36::i;:::-;4541:79;;4630:12;4645:32;4663:4;4669:7;4645:17;:32::i;:::-;4630:47;;4691:7;4687:74;;;4714:14;:20;;;;;;;;;;:36;;4742:7;4714:27;:36::i;:::-;;4777:7;4438:353;-1:-1:-1;;;;4438:353:13:o;3987:348::-;4073:4;4089:40;4132:36;:34;:36::i;:::-;4089:79;;4178:12;4193:31;4210:4;4216:7;4193:16;:31::i;:::-;4178:46;;4238:7;4234:71;;;4261:14;:20;;;;;;;;;;:33;;4286:7;4261:24;:33::i;1767:587:47:-;1996:4;-1:-1:-1;;;;;;2023:52:47;;-1:-1:-1;;;2023:52:47;;:96;;;2079:40;2107:11;2079:27;:40::i;:::-;2023:175;;;;2135:63;2186:11;2135:50;:63::i;:::-;2023:250;;;;2214:59;2261:11;2214:46;:59::i;:::-;2023:324;;;;2289:58;2335:11;2289:45;:58::i;896:203:45:-;981:4;-1:-1:-1;;;;;;1004:48:45;;-1:-1:-1;;;1004:48:45;;:88;;;1056:36;1080:11;1056:23;:36::i;11622:231:27:-;11699:21;11737:37;11754:19;11737:16;:37::i;:::-;11732:61;;-1:-1:-1;11791:1:27;;11622:231;-1:-1:-1;11622:231:27:o;11732:61::-;-1:-1:-1;;;;;;11810:36:27;;;;;:15;:36;;;;;;-1:-1:-1;;;;;11810:36:27;;11622:231::o;7854:597::-;7948:29;7964:12;7948:15;:29::i;:::-;8015:22;;-1:-1:-1;;;;;8015:22:27;;;7992:45;;;;7988:94;;8062:19;8046:36;;-1:-1:-1;;;8046:36:27;;;;;;;;:::i;:::-;;;;;;;;7988:94;8097:8;;:46;;-1:-1:-1;;;8097:46:27;;-1:-1:-1;;;;;8097:8:27;;;;:25;;:46;;8123:19;;8097:46;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8092:98;;8170:19;8152:38;;-1:-1:-1;;;8152:38:27;;;;;;;;:::i;8092:98::-;8206:47;:22;-1:-1:-1;;;;;8206:47:27;;:26;:47::i;:::-;8201:101;;8282:19;8262:40;;-1:-1:-1;;;8262:40:27;;;;;;;;:::i;8201:101::-;-1:-1:-1;;;;;8312:36:27;;;;;;:15;:36;;;;;;:51;;-1:-1:-1;;;;;;8312:51:27;-1:-1:-1;;;;;8312:51:27;;;;;;;;8379:65;;8312:51;;:36;8398:10;;8379:65;;8312:36;8379:65;7854:597;;:::o;8871:165:26:-;8951:4;8974:55;8984:3;-1:-1:-1;;;;;9004:23:26;;8974:9;:55::i;2787:177:12:-;2920:28;;2787:177::o;12199:130:27:-;-1:-1:-1;;;;;12266:18:27;;12262:60;;12293:29;;-1:-1:-1;;;12293:29:27;;;;;;;;;;;12628:177;12715:37;12732:19;12715:16;:37::i;:::-;12710:88;;12778:19;12761:37;;-1:-1:-1;;;12761:37:27;;;;;;;;:::i;3725:792:45:-;3958:36;3996:37;4049:47;4076:19;4049:26;:47::i;:::-;4110:27;;3957:139;;-1:-1:-1;3957:139:45;-1:-1:-1;4110:31:45;4106:294;;4162:9;4157:233;4177:20;:27;4173:1;:31;4157:233;;;4260:11;-1:-1:-1;;;;;4233:38:45;:20;4254:1;4233:23;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;4233:38:45;;4229:147;;4321:19;4341:1;4321:22;;;;;;;;:::i;:::-;;;;;;;4345:11;4302:55;;-1:-1:-1;;;4302:55:45;;;;;;;;;:::i;4229:147::-;4206:3;;4157:233;;;;4106:294;4410:29;:13;4428:10;4410:17;:29::i;:::-;-1:-1:-1;;;;;;;;4449:26:45;;;;;;;:14;:26;;;;;;;;-1:-1:-1;;;;;4449:47:45;;;;;;;;;;;;;:61;;-1:-1:-1;;;;;;4449:61:45;;;;;;;;3725:792::o;8581:304:27:-;8661:50;:22;-1:-1:-1;;;;;8661:50:27;;:29;:50::i;:::-;8656:101;;8737:19;8720:37;;-1:-1:-1;;;8720:37:27;;;;;;;;:::i;8656:101::-;-1:-1:-1;;;;;8774:36:27;;;;;;:15;:36;;;;;;8767:43;;-1:-1:-1;;;;;;8767:43:27;;;8826:52;8846:10;;8826:52;;;8581:304;:::o;10842:774::-;11114:11;11127:36;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11127:36:27;11084:19;2092:41;2113:19;2092:20;:41::i;:::-;11185:362:::1;::::0;;::::1;::::0;::::1;::::0;;;;11231:20:::1;11242:8:::0;11231:20;;;::::1;:::i;:::-;;::::0;;;;::::1;-1:-1:-1::0;;11231:20:27;;;;;;11185:362;;;11231:20:::1;11185:362:::0;;::::1;::::0;;;11303:30;;-1:-1:-1;11303:30:27;;;;;::::1;::::0;;11185:362;;;;;11303:30;::::1;::::0;::::1;-1:-1:-1::0;;;;;;;;;;;;;;;;;11303:30:27::1;;;;;;;;;;;;;;;;11185:362;;;;11528:8;-1:-1:-1::0;;;;;11185:362:27::1;;;;;11358:146;11395:95;;;;;;;;11428:8;11395:95;;;;11464:24;11395:95;;;;::::0;2187:56:6;;;31992:13:49;;2187:56:6;;;31974:32:49;32076:4;32064:17;;;32058:24;32051:32;32044:40;32022:20;;;;32015:70;;;;2187:56:6;;;;;;;;;;31947:18:49;;;;2187:56:6;;;;;;;;-1:-1:-1;;;;;2187:56:6;-1:-1:-1;;;2187:56:6;;;;2070:178;11358:146:27::1;11185:362:::0;;11564:8:::1;::::0;:45:::1;::::0;-1:-1:-1;;;11564:45:27;;11175:372;;-1:-1:-1;;;;;;11564:8:27::1;::::0;:15:::1;::::0;:45:::1;::::0;11580:19;;11175:372;;11564:45:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11558:51;;10842:774:::0;;;;;;;;;;:::o;5395:121:45:-;5479:1;5474;:6;5470:39;;5489:20;;-1:-1:-1;;;5489:20:45;;;;;26540:25:49;;;26581:18;;;26574:34;;;26513:18;;5489:20:45;26366:248:49;12335:111:27;12401:3;12408:1;12401:8;12397:42;;12418:21;;-1:-1:-1;;;12418:21:27;;;;;;;;;;;5160:154:45;5254:28;5271:10;5254:16;:28::i;:::-;5249:58;;5291:16;;-1:-1:-1;;;5291:16:45;;;;;;;;;;;4718:144:48;4818:16;;;4832:1;4818:16;;;;;;;;;4780:20;;4818:16;;;;;;;;;;;-1:-1:-1;4818:16:48;4812:22;;4853:2;4844:3;4848:1;4844:6;;;;;;;;:::i;:::-;;;;;;:11;;;;;4718:144;;;:::o;3419:1293::-;3650:17;3637:2;2325:21:27;2341:4;2325:15;:21::i;:::-;3679:17:48::1;3710:3;3699:15;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;3699:15:48;;::::1;::::0;;;3749:100:::1;::::0;::::1;::::0;;-1:-1:-1;;;;;3749:100:48;::::1;::::0;;-1:-1:-1;;;;;3749:100:48;::::1;3699:15;3749:100:::0;::::1;::::0;;;;;;;3699:15;-1:-1:-1;3724:135:48::1;::::0;:11:::1;:135::i;:::-;3870:19;3892:47;3907:10;3919:19;3892:14;:47::i;:::-;3870:69;;3949:28;3965:11;3949:15;:28::i;:::-;3999:643;4055:19;4098:34;4112:19;4098:13;:34::i;:::-;4180:329;;;;;;;;4237:10;-1:-1:-1::0;;;;;4180:329:48::1;;;;;4290:25;:23;:25::i;:::-;-1:-1:-1::0;;;;;4180:329:48::1;;;;;4347:2;-1:-1:-1::0;;;;;4180:329:48::1;;;;;4383:11;-1:-1:-1::0;;;;;4180:329:48::1;;;;;4443:4;-1:-1:-1::0;;;;;4180:329:48::1;;;;;4486:4;4180:329;;::::0;4152:371:::1;;;;;;;;:::i;:::-;;;;;;;;;;;;;4547:8;4595:4;4623:8;3999:20;:643::i;:::-;3987:655;;4652:53;4668:25;:23;:25::i;:::-;4695:9;4652:15;:53::i;:::-;3669:1043;;3419:1293:::0;;;;;;;;;:::o;3478:178:16:-;2226:16;:14;:16::i;:::-;3536:25:::1;3564:21;:19;:21::i;:::-;3595:17:::0;;-1:-1:-1;;3595:17:16::1;::::0;;;-1:-1:-1;3627:22:16::1;966:10:15::0;3636:12:16::1;3627:22;;;;;;:::i;:::-;;;;;;;;3526:130;3478:178::o:0;9117:115:26:-;9180:7;9206:19;9214:3;4556:18;;4474:107;9574:156;9648:7;9698:22;9702:3;9714:5;9698:3;:22::i;2496:145:16:-;2543:4;2559:25;2587:21;:19;:21::i;:::-;2625:9;;;;2496:145;-1:-1:-1;;2496:145:16:o;9071:205:14:-;9129:30;;3147:66;9186:27;8819:122;890:145:28;6929:20:14;:18;:20::i;:::-;981:47:28::1;1015:12;981:33;:47::i;1099:145:29:-:0;6929:20:14;:18;:20::i;:::-;1190:47:29::1;1225:11;1190:34;:47::i;863:169:30:-:0;6929:20:14;:18;:20::i;:::-;966:59:30::1;1005:19;966:38;:59::i;1302:227:46:-:0;6929:20:14;:18;:20::i;:::-;1424:33:46::1;1451:5;1424:26;:33::i;:::-;1467:55;1493:6;1501:20;1467:25;:55::i;3170:176:16:-:0;1979:19;:17;:19::i;:::-;3229:25:::1;3257:21;:19;:21::i;:::-;3288:16:::0;;-1:-1:-1;;3288:16:16::1;3300:4;3288:16;::::0;;3229:49;-1:-1:-1;3319:20:16::1;3326:12;966:10:15::0;;887:96;12452:170:27;12535:10;;:58;;-1:-1:-1;;;12535:58:27;;12555:37;;;;-1:-1:-1;;;;;;;12555:37:27;12535:58;;;26765:56:49;-1:-1:-1;;;12535:10:27;;;-1:-1:-1;;;;;12535:10:27;;:19;;26738:18:49;;12535:58:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12531:84;;;12602:13;;-1:-1:-1;;;12602:13:27;;;;;;;;;;;12811:209;12915:44;12931:19;12952:6;12915:15;:44::i;:::-;12910:103;;12968:45;;-1:-1:-1;;;12968:45:27;;-1:-1:-1;;;;;27022:31:49;;12968:45:27;;;27004:50:49;-1:-1:-1;;;;;27090:32:49;;27070:18;;;27063:60;26977:18;;12968:45:27;26832:297:49;12048:145:27;12124:8;;-1:-1:-1;;;;;12124:8:27;12102:10;:31;12098:88;;12164:8;;12142:44;;-1:-1:-1;;;12142:44:27;;;;-1:-1:-1;;;;;12164:8:27;;12175:10;;12142:44;;;:::i;12098:88::-;12048:145::o;2360:1275:47:-;2458:39;2511:12;;;;:7;:12;:::i;:::-;2500:46;;;;;;;:::i;:::-;2458:88;;2690:13;:33;;;-1:-1:-1;;;;;2659:64:47;:7;:27;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;2659:64:47;;2655:193;;2774:27;;;;;;;;:::i;:::-;2803:33;;;;2746:91;;-1:-1:-1;;;2746:91:47;;-1:-1:-1;;;;;29023:31:49;;;2746:91:47;;;29005:50:49;29091:31;;29071:18;;;29064:59;28978:18;;2746:91:47;28835:294:49;2655:193:47;2940:20;2974:14;;;;:7;:14;:::i;:::-;2963:37;;;;;;;:::i;:::-;2940:60;;3030:13;:31;;;-1:-1:-1;;;;;3014:47:47;:12;-1:-1:-1;;;;;3014:47:47;;3010:150;;3117:31;;;;3084:65;;-1:-1:-1;;;3084:65:47;;;;3103:12;;3084:65;;;:::i;3010:150::-;3185:28;;3169:45;;:15;:45::i;:::-;3241:33;;;;3225:69;;3276:17;;3225:15;:69::i;:::-;3304:29;3319:13;3304:14;:29::i;:::-;3454:7;:17;;;3418:13;:22;;;-1:-1:-1;;;;;3349:279:47;3376:13;:28;;;-1:-1:-1;;;;;3349:279:47;;3496:13;:28;;;3485:53;;;;;;;;;;;;:::i;:::-;3552:27;;;;;;;;:::i;:::-;3593:25;:23;:25::i;:::-;3349:279;;;;;;;;:::i;:::-;;;;;;;;2448:1187;;2360:1275;:::o;11317:144:26:-;11394:4;11417:37;11427:3;11447:5;11417:9;:37::i;1250:207:13:-;1403:38;;1250:207::o;10270:300:26:-;10333:16;10361:22;10386:19;10394:3;10386:7;:19::i;4429:530:9:-;4521:18;;:::i;:::-;4785:99;4802:6;:15;;;-1:-1:-1;;;;;4785:99:9;4819:6;:13;;;-1:-1:-1;;;;;4785:99:9;4852:6;:18;;;4834:36;;:15;:36;;;;:::i;:::-;4872:6;:11;;;-1:-1:-1;;;;;4785:99:9;:16;:99::i;:::-;-1:-1:-1;;;;;4755:130:9;;;-1:-1:-1;4891:44:9;4919:15;4891:44;:18;;;:44;4755:6;4429:530::o;4586:505:45:-;-1:-1:-1;;;;;4719:26:45;;;4697:19;4719:26;;;:14;:26;;;;;;;;-1:-1:-1;;;;;4719:47:45;;;;;;;;;;;;4776:85;;4814:47;;-1:-1:-1;;;4814:47:45;;-1:-1:-1;;;;;30713:32:49;;4814:47:45;;;30695:51:49;-1:-1:-1;;;;;30782:31:49;;30762:18;;;30755:59;30668:18;;4814:47:45;30523:297:49;4776:85:45;-1:-1:-1;;;;;4878:26:45;;;;;;:14;:26;;;;;;;;-1:-1:-1;;;;;4878:47:45;;;;;;;;;4871:54;;-1:-1:-1;;;;;;4871:54:45;;;5022:28;4893:10;5022:16;:28::i;:::-;5017:67;;5052:32;:13;5073:10;5052:20;:32::i;3140:605:29:-;3329:66;:14;3388:5;3329:41;:66::i;:::-;-1:-1:-1;;;;;3405:37:29;;;;;;:16;:37;;;;;:75;;3465:14;3405:59;:75::i;:::-;3491:65;:13;3549:5;3491:40;:65::i;:::-;-1:-1:-1;;;;;3566:36:29;;;;;;:15;:36;;;;;:73;;3625:13;3566:58;:73::i;:::-;3687:19;-1:-1:-1;;;;;3655:83:29;3675:10;-1:-1:-1;;;;;3655:83:29;;3708:14;3724:13;3655:83;;;;;;;:::i;4381:197:12:-;4469:22;4477:4;4483:7;4469;:22::i;:::-;4464:108;;4547:7;4556:4;4514:47;;-1:-1:-1;;;4514:47:12;;;;;;;;;:::i;7894:388::-;7972:4;7988:30;8021:26;:24;:26::i;:::-;7988:59;;8061:22;8069:4;8075:7;8061;:22::i;:::-;8057:219;;;8133:5;8099:14;;;;;;;;;;;-1:-1:-1;;;;;8099:31:12;;;;;;;;;;:39;;-1:-1:-1;;8099:39:12;;;8157:40;966:10:15;;8099:14:12;;8157:40;;8133:5;8157:40;8218:4;8211:11;;;;;8057:219;8260:5;8253:12;;;;;8634:156:26;8707:4;8730:53;8738:3;-1:-1:-1;;;;;8758:23:26;;8730:7;:53::i;7270:387:12:-;7347:4;7363:30;7396:26;:24;:26::i;:::-;7363:59;;7437:22;7445:4;7451:7;7437;:22::i;:::-;7432:219;;7475:8;:14;;;;;;;;;;;-1:-1:-1;;;;;7475:31:12;;;;;;;;;:38;;-1:-1:-1;;7475:38:12;7509:4;7475:38;;;7559:12;966:10:15;;887:96;7559:12:12;-1:-1:-1;;;;;7532:40:12;7550:7;-1:-1:-1;;;;;7532:40:12;7544:4;7532:40;;;;;;;;;;7593:4;7586:11;;;;;8316:150:26;8386:4;8409:50;8414:3;-1:-1:-1;;;;;8434:23:26;;8409:4;:50::i;4373:373:46:-;4565:4;-1:-1:-1;;;;;;4592:48:46;;-1:-1:-1;;;4592:48:46;;:95;;-1:-1:-1;;;;;;;4644:43:46;;-1:-1:-1;;;4644:43:46;4592:95;:147;;;;4703:36;4727:11;4703:23;:36::i;1609:210:30:-;1694:4;-1:-1:-1;;;;;;1717:55:30;;-1:-1:-1;;;1717:55:30;;:95;;;1776:36;1800:11;1771:206:29;1856:4;-1:-1:-1;;;;;;1879:51:29;;-1:-1:-1;;;1879:51:29;;:91;;;1934:36;1958:11;1499:205:28;1584:4;-1:-1:-1;;;;;;1607:50:28;;-1:-1:-1;;;1607:50:28;;:90;;;1661:36;1685:11;1661:23;:36::i;10804:129:26:-;10871:4;10894:32;10899:3;10919:5;10894:4;:32::i;4264:129::-;4337:4;4360:21;;;:14;;;;;:21;;;;;;:26;;;4264:129::o;11101:135::-;11171:4;11194:35;11202:3;11222:5;11194:7;:35::i;4677:721:47:-;1979:19:16;:17;:19::i;:::-;4828:10:47::1;:21;;;1248:30:46;1267:10;1248:18;:30::i;:::-;4876::47::0;;2092:41:27::2;4876:30:47::0;2092:20:27::2;:41::i;:::-;4922:20:47::3;4956:10;:20;;;4945:45;;;;;;;;;;;;:::i;:::-;5021:10:::0;;4922:68;;-1:-1:-1;5041:27:47::3;5021:10:::0;5041:15:::3;:27::i;:::-;5084:9;5079:140;5099:10;5095:1;:14;5079:140;;;5138:10;:21;;;-1:-1:-1::0;;;;;5130:43:47::3;;5174:10;5194:4;5201:3;5205:1;5201:6;;;;;;;;:::i;:::-;;;;;;;5130:78;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5111:3;;;;;5079:140;;;;5229:60;5247:10;:21;;;5278:4;5285:3;5229:17;:60::i;:::-;5299:92;5325:10;:30;;;5357:10;:21;;;5380:10;5299:25;:92::i;:::-;4912:486;;1288:1:46::2;2008::16::1;4677:721:47::0;:::o;9133:1620:27:-;9398:17;9368:19;2427:38;2445:19;2427:17;:38::i;:::-;9427:25:::1;9443:8;9427:15;:25::i;:::-;9462;9478:8;9462:15;:25::i;:::-;9497:28;9513:4;:11;9497:15;:28::i;:::-;9537:11;9550:36;9602:98;9618:19;9639:8;9649:4;9655:8;9665:24;9691:8;9602:15;:98::i;:::-;9536:164:::0;;-1:-1:-1;9536:164:27;-1:-1:-1;9711:17:27::1;-1:-1:-1::0;;;;;9742:22:27;::::1;9738:538;;9796:3;9784:9;:15;9780:65;;;9808:37;::::0;-1:-1:-1;;;9808:37:27;;::::1;::::0;::::1;26540:25:49::0;;;9835:9:27::1;26581:18:49::0;;;26574:34;26513:18;;9808:37:27::1;26366:248:49::0;9780:65:27::1;9871:8;;;;;;;;;-1:-1:-1::0;;;;;9871:8:27::1;-1:-1:-1::0;;;;;9871:25:27::1;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9860:38;;9989:8;9970:7;:16;;:27;-1:-1:-1::0;;;;;9970:27:27::1;;;-1:-1:-1::0;;;;;9970:27:27::1;;;::::0;::::1;10026:8;-1:-1:-1::0;;;;;10011:32:27::1;;10051:3;10011:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10096:3;10084:9;:15;;;;:::i;:::-;10072:27;;9738:538;;;10134:9;:14:::0;10130:56:::1;;10157:29;::::0;-1:-1:-1;;;10157:29:27;;10176:9:::1;10157:29;::::0;::::1;3436:25:49::0;3409:18;;10157:29:27::1;3290:177:49::0;10130:56:27::1;10200:65;-1:-1:-1::0;;;;;10200:33:27;::::1;10234:10;10254:4;10261:3:::0;10200:33:::1;:65::i;:::-;10319:8;::::0;10286:48:::1;::::0;-1:-1:-1;;;10286:48:27;;-1:-1:-1;;;;;10286:24:27;;::::1;::::0;::::1;::::0;:48:::1;::::0;10319:8;;::::1;::::0;10330:3;;10286:48:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;10357:8:27::1;::::0;:47:::1;::::0;-1:-1:-1;;;10357:47:27;;-1:-1:-1;;;;;10357:8:27;;::::1;::::0;:17:::1;::::0;:47:::1;::::0;10375:19;;10396:7;;10357:47:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10345:59:::0;-1:-1:-1;10419:13:27;;10415:282:::1;;10529:37;::::0;10512:12:::1;::::0;10529:10:::1;::::0;10552:9;;10512:12;10529:37;10512:12;10529:37;10552:9;10529:10;:37:::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10511:55;;;10585:7;10580:56;;10614:10;10626:9;10601:35;;-1:-1:-1::0;;;10601:35:27::1;;;;;;;;;:::i;10580:56::-;10655:31;::::0;3436:25:49;;;10664:10:27::1;::::0;10655:31:::1;::::0;3424:2:49;3409:18;10655:31:27::1;;;;;;;10434:263;10415:282;10712:34;::::0;10736:9;;10724:10:::1;::::0;10712:34:::1;::::0;;;::::1;9417:1336;;;9133:1620:::0;;;;;;;;;:::o;4752:309:46:-;-1:-1:-1;;;;;4841:32:46;;;;;;:17;:32;;;;;;;;:43;;;;;;;;;;;4837:104;;;4893:48;;-1:-1:-1;;;4893:48:46;;-1:-1:-1;;;;;32964:31:49;;4893:48:46;;;32946:50:49;33012:18;;;33005:34;;;32919:18;;4893:48:46;32774:271:49;4837:104:46;-1:-1:-1;;;;;4951:27:46;;;;;;;:12;:27;;;;;;;;:43;;;;;;;;;;;;;;;;;;5004:32;;;:17;:32;;;;;:43;;;;;;;;;;:50;;-1:-1:-1;;5004:50:46;;;;;;4752:309::o;2909:126:16:-;2972:8;:6;:8::i;:::-;2967:62;;3003:15;;-1:-1:-1;;;3003:15:16;;;;;;;;;;;1147:162;1270:23;;1147:162::o;4923:118:26:-;4990:7;5016:3;:11;;5028:5;5016:18;;;;;;;;:::i;:::-;;;;;;;;;5009:25;;4923:118;;;;:::o;7082:141:14:-;7149:17;:15;:17::i;:::-;7144:73;;7189:17;;-1:-1:-1;;;7189:17:14;;;;;;;;;;;1041:184:28;6929:20:14;:18;:20::i;:::-;1142:14:28::1;:29:::0;;-1:-1:-1;;;;;;1142:29:28::1;-1:-1:-1::0;;;;;1142:29:28;::::1;;::::0;;1181:37:::1;-1:-1:-1::0;;;;;;;;;;;1142:29:28;1181:10:::1;:37::i;1250:150:29:-:0;6929:20:14;:18;:20::i;:::-;1351:42:29::1;-1:-1:-1::0;;;;;;;;;;;1381:11:29::1;1351:10;:42::i;1038:179:30:-:0;6929:20:14;:18;:20::i;:::-;1151:59:30::1;-1:-1:-1::0;;;;;;;;;;;1190:19:30::1;1151:10;:59::i;1535:134:46:-:0;6929:20:14;:18;:20::i;:::-;1622:40:46::1;-1:-1:-1::0;;;;;;;;;;;1656:5:46::1;1622:10;:40::i;2489:188:27:-:0;6929:20:14;:18;:20::i;:::-;2605:65:27::1;2641:6;2649:20;2605:35;:65::i;2709:128:16:-:0;2774:8;:6;:8::i;:::-;2770:61;;;2805:15;;-1:-1:-1;;;2805:15:16;;;;;;;;;;;2936:477:48;3269:92;3285:75;3300:13;:24;;;3326:13;:33;;;3285:14;:75::i;3269:92::-;3371:35;3392:13;3371:20;:35::i;5581:109:26:-;5637:16;5672:3;:11;;5665:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5581:109;;;:::o;6554:201:9:-;6688:7;6710:40;6715:8;6734:15;6745:4;6734:8;:15;:::i;:::-;6725:24;;:6;:24;:::i;:::-;6710:4;:40::i;:::-;6703:47;6554:201;-1:-1:-1;;;;;6554:201:9:o;5833:451::-;5936:16;;5932:348;;;5981:6;:15;;;-1:-1:-1;;;;;5966:30:9;:6;:11;;;-1:-1:-1;;;;;5966:30:9;;;:50;;;-1:-1:-1;6000:11:9;;;;-1:-1:-1;;;;;6000:16:9;;5966:50;5962:110;;;6056:6;6035:28;;-1:-1:-1;;;6035:28:9;;;;;;;;:::i;5962:110::-;6083:14;6079:71;;;6116:25;;-1:-1:-1;;;6116:25:9;;;;;;;;;;;5932:348;6174:11;;;;-1:-1:-1;;;;;6174:16:9;;;;:40;;-1:-1:-1;6194:15:9;;;;-1:-1:-1;;;;;6194:20:9;;;6174:40;6170:104;;;6258:6;6233:32;;-1:-1:-1;;;6233:32:9;;;;;;;;:::i;5081:700::-;5336:20;;5299:16;;5318:38;;-1:-1:-1;;;5336:20:9;;;;5318:15;:38;:::i;:::-;5299:57;-1:-1:-1;5366:13:9;;5362:193;;5432:17;;;;5451:15;;5415:77;;-1:-1:-1;;;;;5432:17:9;;;;5451:15;;;5468:8;;-1:-1:-1;;;5478:13:9;;;;5415:16;:77::i;:::-;5389:104;;-1:-1:-1;;;;;5389:104:9;;;;-1:-1:-1;;;;;;5502:46:9;;;;-1:-1:-1;;;5532:15:9;5502:46;;;;;;5362:193;5592:15;;;;5609;;5587:38;;-1:-1:-1;;;;;5587:38:9;;;;5609:15;5587:4;:38::i;:::-;5561:65;;5653:16;;5632:37;;-1:-1:-1;;;5632:37:9;-1:-1:-1;;;;;;5632:37:9;;;-1:-1:-1;;;;;5561:65:9;;;5632:37;;;;5695:15;;;;5732:11;;;;;5716:27;;-1:-1:-1;;;5716:27:9;5675:35;;;;5716:27;5561:65;5675:17;;5716:27;5755:21;;;;;5653:6;;5755:21;:::i;:::-;;;;;;;;5173:608;5081:700;;:::o;2815:1368:26:-;2881:4;3010:21;;;:14;;;:21;;;;;;3046:13;;3042:1135;;3413:18;3434:12;3445:1;3434:8;:12;:::i;:::-;3480:18;;3413:33;;-1:-1:-1;3460:17:26;;3480:22;;3501:1;;3480:22;:::i;:::-;3460:42;;3535:9;3521:10;:23;3517:378;;3564:17;3584:3;:11;;3596:9;3584:22;;;;;;;;:::i;:::-;;;;;;;;;3564:42;;3731:9;3705:3;:11;;3717:10;3705:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;3844:25;;;:14;;;:25;;;;;:36;;;3517:378;3973:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;4076:3;:14;;:21;4091:5;4076:21;;;;;;;;;;;4069:28;;;4119:4;4112:11;;;;;;;2241:406;2304:4;2325:21;2335:3;2340:5;2325:9;:21::i;:::-;2320:321;;-1:-1:-1;2362:23:26;;;;;;;;:11;:23;;;;;;;;;;;;;2544:18;;2520:21;;;:14;;;:21;;;;;;:42;;;;2576:11;;2320:321;-1:-1:-1;2625:5:26;2618:12;;7169:283:27;7254:4;-1:-1:-1;;;;;;7277:52:27;;-1:-1:-1;;;7277:52:27;;:124;;-1:-1:-1;;;;;;;7345:56:27;;-1:-1:-1;;;7345:56:27;7277:124;:168;;;-1:-1:-1;;;;;;;7405:40:27;;-1:-1:-1;;;7405:40:27;7270:175;7169:283;-1:-1:-1;;7169:283:27:o;1695:212:13:-;1780:4;-1:-1:-1;;;;;;1803:57:13;;-1:-1:-1;;;1803:57:13;;:97;;;1864:36;1888:11;1864:23;:36::i;5404:311:47:-;5532:10;;5511:18;5553:156;5573:10;5569:1;:14;5553:156;;;5641:9;-1:-1:-1;;;;;5608:42:47;:29;5623:5;5630:3;5634:1;5630:6;;;;;;;;:::i;:::-;;;;;;;5608:14;:29::i;:::-;-1:-1:-1;;;;;5608:42:47;;5604:94;;5680:9;5691:3;5695:1;5691:6;;;;;;;;:::i;:::-;;;;;;;5659:39;;-1:-1:-1;;;5659:39:47;;;;;;;;;:::i;5604:94::-;5585:3;;5553:156;;2684:181:29;-1:-1:-1;;;;;2797:37:29;;;;;;:16;:37;;;;;:61;;2844:6;2852:5;2797:46;:61::i;1702:188:22:-;1802:81;1822:5;1844;-1:-1:-1;;;;;1844:18:22;;1865:4;1871:2;1875:5;1829:53;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1829:53:22;;;;;;;;;;;1802:19;:81::i;8485:120:14:-;8535:4;8558:26;:24;:26::i;:::-;:40;-1:-1:-1;;;8558:40:14;;;;;;-1:-1:-1;8485:120:14:o;2683:347:27:-;6929:20:14;:18;:20::i;:::-;2829:37:27::1;2845:20;-1:-1:-1::0;;;;;2829:37:27::1;:15;:37::i;:::-;2877:8;:40:::0;;-1:-1:-1;;;;;;2877:40:27::1;-1:-1:-1::0;;;;;2877:40:27;::::1;::::0;;::::1;::::0;;;2945:22:::1;::::0;;-1:-1:-1;;;2945:22:27;;;;:20:::1;::::0;:22:::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;2877:40;2945:22:::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2927:10;:41:::0;;-1:-1:-1;;;;;2978:45:27;;::::1;-1:-1:-1::0;;;;;;;;;;;2927:41:27;;;::::1;-1:-1:-1::0;;;2927:41:27::1;2978:45:::0;;;;-1:-1:-1;;;;;;2978:45:27;;;;;;;::::1;::::0;;-1:-1:-1;2683:347:27:o;3641:1030:47:-;1979:19:16;:17;:19::i;:::-;3756:20:47::1;3790:13;:28;;;3779:53;;;;;;;;;;;;:::i;:::-;3863:10:::0;;3756:76;;-1:-1:-1;3883:27:47::1;3863:10:::0;3883:15:::1;:27::i;:::-;3921:39;3937:13;:22;;;3921:15;:39::i;:::-;3970:44;3989:13;:24;;;3970:18;:44::i;:::-;4030:9;4025:450;4045:10;4041:1;:14;4025:450;;;4076:10;4089:3;4093:1;4089:6;;;;;;;;:::i;:::-;;;;;;;4076:19;;4109:13;4125:44;4140:13;:24;;;4166:2;4125:14;:44::i;:::-;4109:60:::0;-1:-1:-1;;;;;;4188:22:47;::::1;4205:4;4188:22;::::0;:48:::1;;;4214:22;4230:5;4214:15;:22::i;:::-;4184:281;;;4264:13;:24;;;-1:-1:-1::0;;;;;4256:46:47::1;;4303:5;4310:13;:22;;;4334:2;4256:81;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4184:281;;;4392:13;:24;;;-1:-1:-1::0;;;;;4376:46:47::1;;4423:13;:22;;;4447:2;4376:74;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4184:281;-1:-1:-1::0;;4057:3:47::1;;4025:450;;;;4485:72;4503:13;:24;;;4529:13;:22;;;4553:3;4485:17;:72::i;:::-;4567:97;4592:13;:33;;;4627:13;:24;;;4653:10;4567:24;:97::i;6883:99:9:-:0;6942:7;6968:1;6964;:5;:13;;6976:1;6964:13;;;-1:-1:-1;6972:1:9;;6883:99;-1:-1:-1;6883:99:9:o;3443:202:12:-;3528:4;-1:-1:-1;;;;;;3551:47:12;;-1:-1:-1;;;3551:47:12;;:87;;-1:-1:-1;;;;;;;;;;1134:40:17;;;3602:36:12;1035:146:17;5721:324:47;5826:26;;-1:-1:-1;;;5826:26:47;;;;;3436:25:49;;;5795:15:47;;-1:-1:-1;;;;;5826:22:47;;;;;3409:18:49;;5826:26:47;;;;;;;;;;;;;;;;;;-1:-1:-1;5826:26:47;;;;;;;;-1:-1:-1;;5826:26:47;;;;;;;;;;;;:::i;:::-;;;5822:217;;-1:-1:-1;6026:1:47;6011:17;;5822:217;5895:2;-1:-1:-1;5888:9:47;;2516:1790:9;2734:18;;-1:-1:-1;;;2734:18:9;;;;2733:19;;:41;;-1:-1:-1;2756:18:9;;2733:41;2729:68;;;2516:1790;;;:::o;2729:68::-;2820:15;;;2860:17;;;-1:-1:-1;;;;;2820:15:9;;;;2860:17;;;2803:14;;2902:38;;-1:-1:-1;;;2920:20:9;;;;2902:15;:38;:::i;:::-;2883:57;-1:-1:-1;2951:13:9;;2947:271;;2987:8;2978:6;:17;2974:48;;;3004:18;;-1:-1:-1;;;3004:18:9;;;;;;;;;;;2974:48;3142:13;;;;3097:59;;3114:8;;3124:6;;3132:8;;-1:-1:-1;;;3142:13:9;;-1:-1:-1;;;;;3142:13:9;3097:16;:59::i;:::-;3165:46;;-1:-1:-1;;;;3165:46:9;-1:-1:-1;;;3195:15:9;3165:46;;;;;;3088:68;-1:-1:-1;2947:271:9;3239:13;3228:8;:24;3224:302;;;-1:-1:-1;;;;;3348:26:9;;3344:97;;3383:58;;-1:-1:-1;;;3383:58:9;;;;;26540:25:49;;;26581:18;;;26574:34;;;26513:18;;3383:58:9;26366:248:49;3344:97:9;3481:8;3491:13;3506:12;3456:63;;-1:-1:-1;;;3456:63:9;;;;;;;;;;:::i;3224:302::-;3544:13;3535:6;:22;3531:594;;;3582:13;;;;;-1:-1:-1;;;3582:13:9;;-1:-1:-1;;;;;3582:13:9;;3567:12;;3582:13;;3921:8;;3582:13;3921:8;:::i;:::-;3894:22;3910:6;3894:13;:22;:::i;:::-;3893:37;;;;:::i;:::-;3892:46;;;;:::i;:::-;3865:73;-1:-1:-1;;;;;;3951:26:9;;3947:95;;3986:56;;-1:-1:-1;;;3986:56:9;;;;;26540:25:49;;;26581:18;;;26574:34;;;26513:18;;3986:56:9;26366:248:49;3947:95:9;4079:16;4097:6;4105:12;4057:61;;-1:-1:-1;;;4057:61:9;;;;;;;;;;:::i;3531:594::-;4130:23;4140:13;4130:23;;:::i;:::-;4228:33;;-1:-1:-1;;;;;;4228:33:9;-1:-1:-1;;;;;4228:33:9;;;;;4272:29;;3436:25:49;;;4228:33:9;;-1:-1:-1;4272:29:9;;3424:2:49;3409:18;4272:29:9;;;;;;;2618:1688;;;2516:1790;;;:::o;4059:629:22:-;4478:23;4504:33;-1:-1:-1;;;;;4504:27:22;;4532:4;4504:27;:33::i;:::-;4478:59;;4551:10;:17;4572:1;4551:22;;:57;;;;;4589:10;4578:30;;;;;;;;;;;;:::i;:::-;4577:31;4551:57;4547:135;;;4664:5;4631:40;;-1:-1:-1;;;4631:40:22;;;;;;;;:::i;2955:179:29:-;-1:-1:-1;;;;;3067:36:29;;;;;;:15;:36;;;;;:60;;3113:6;3121:5;3067:45;:60::i;2705:151:24:-;2780:12;2811:38;2833:6;2841:4;2847:1;2780:12;3421;3435:23;3462:6;-1:-1:-1;;;;;3462:11:24;3481:5;3488:4;3462:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3420:73;;;;3510:55;3537:6;3545:7;3554:10;3510:26;:55::i;:::-;3503:62;3180:392;-1:-1:-1;;;;;;3180:392:24:o;4625:582::-;4769:12;4798:7;4793:408;;4821:19;4829:10;4821:7;:19::i;:::-;4793:408;;;5045:17;;:22;:49;;;;-1:-1:-1;;;;;;5071:18:24;;;:23;5045:49;5041:119;;;5138:6;5121:24;;-1:-1:-1;;;5121:24:24;;;;;;;;:::i;5041:119::-;-1:-1:-1;5180:10:24;5173:17;;5743:516;5874:17;;:21;5870:383;;6102:10;6096:17;6158:15;6145:10;6141:2;6137:19;6130:44;5870:383;6225:17;;-1:-1:-1;;;6225:17:24;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:131:49:-;-1:-1:-1;;;;;89:31:49;;79:42;;69:70;;135:1;132;125:12;150:134;218:20;;247:31;218:20;247:31;:::i;:::-;150:134;;;:::o;289:247::-;348:6;401:2;389:9;380:7;376:23;372:32;369:52;;;417:1;414;407:12;369:52;456:9;443:23;475:31;500:5;475:31;:::i;541:286::-;599:6;652:2;640:9;631:7;627:23;623:32;620:52;;;668:1;665;658:12;620:52;694:23;;-1:-1:-1;;;;;;746:32:49;;736:43;;726:71;;793:1;790;783:12;1024:118;1110:5;1103:13;1096:21;1089:5;1086:32;1076:60;;1132:1;1129;1122:12;1147:382;1212:6;1220;1273:2;1261:9;1252:7;1248:23;1244:32;1241:52;;;1289:1;1286;1279:12;1241:52;1328:9;1315:23;1347:31;1372:5;1347:31;:::i;:::-;1397:5;-1:-1:-1;1454:2:49;1439:18;;1426:32;1467:30;1426:32;1467:30;:::i;:::-;1516:7;1506:17;;;1147:382;;;;;:::o;1534:171::-;1601:20;;-1:-1:-1;;;;;1650:30:49;;1640:41;;1630:69;;1695:1;1692;1685:12;1710:184;1768:6;1821:2;1809:9;1800:7;1796:23;1792:32;1789:52;;;1837:1;1834;1827:12;1789:52;1860:28;1878:9;1860:28;:::i;2008:203::-;-1:-1:-1;;;;;2172:32:49;;;;2154:51;;2142:2;2127:18;;2008:203::o;2216:289::-;2258:3;2296:5;2290:12;2323:6;2318:3;2311:19;2379:6;2372:4;2365:5;2361:16;2354:4;2349:3;2345:14;2339:47;2431:1;2424:4;2415:6;2410:3;2406:16;2402:27;2395:38;2494:4;2487:2;2483:7;2478:2;2470:6;2466:15;2462:29;2457:3;2453:39;2449:50;2442:57;;;2216:289;;;;:::o;2510:220::-;2659:2;2648:9;2641:21;2622:4;2679:45;2720:2;2709:9;2705:18;2697:6;2679:45;:::i;2735:319::-;2802:6;2810;2863:2;2851:9;2842:7;2838:23;2834:32;2831:52;;;2879:1;2876;2869:12;2831:52;2902:28;2920:9;2902:28;:::i;:::-;2892:38;;2980:2;2969:9;2965:18;2952:32;2993:31;3018:5;2993:31;:::i;3059:226::-;3118:6;3171:2;3159:9;3150:7;3146:23;3142:32;3139:52;;;3187:1;3184;3177:12;3139:52;-1:-1:-1;3232:23:49;;3059:226;-1:-1:-1;3059:226:49:o;3472:460::-;3548:6;3556;3564;3617:2;3605:9;3596:7;3592:23;3588:32;3585:52;;;3633:1;3630;3623:12;3585:52;3672:9;3659:23;3691:31;3716:5;3691:31;:::i;:::-;3741:5;-1:-1:-1;3765:37:49;3798:2;3783:18;;3765:37;:::i;:::-;3755:47;;3854:2;3843:9;3839:18;3826:32;3867:33;3892:7;3867:33;:::i;:::-;3919:7;3909:17;;;3472:460;;;;;:::o;3937:367::-;4005:6;4013;4066:2;4054:9;4045:7;4041:23;4037:32;4034:52;;;4082:1;4079;4072:12;4034:52;4127:23;;;-1:-1:-1;4226:2:49;4211:18;;4198:32;4239:33;4198:32;4239:33;:::i;4309:446::-;4362:3;4400:5;4394:12;4427:6;4422:3;4415:19;4459:4;4454:3;4450:14;4443:21;;4498:4;4491:5;4487:16;4521:1;4531:199;4545:6;4542:1;4539:13;4531:199;;;4610:13;;-1:-1:-1;;;;;4606:39:49;4594:52;;4675:4;4666:14;;;;4703:17;;;;4642:1;4560:9;4531:199;;;-1:-1:-1;4746:3:49;;4309:446;-1:-1:-1;;;;4309:446:49:o;4760:261::-;4939:2;4928:9;4921:21;4902:4;4959:56;5011:2;5000:9;4996:18;4988:6;4959:56;:::i;5026:560::-;5111:6;5119;5127;5135;5188:3;5176:9;5167:7;5163:23;5159:33;5156:53;;;5205:1;5202;5195:12;5156:53;5244:9;5231:23;5263:31;5288:5;5263:31;:::i;:::-;5313:5;-1:-1:-1;5337:37:49;5370:2;5355:18;;5337:37;:::i;:::-;5026:560;;5327:47;;-1:-1:-1;;;;5447:2:49;5432:18;;5419:32;;5550:2;5535:18;5522:32;;5026:560::o;5773:367::-;5836:8;5846:6;5900:3;5893:4;5885:6;5881:17;5877:27;5867:55;;5918:1;5915;5908:12;5867:55;-1:-1:-1;5941:20:49;;-1:-1:-1;;;;;5973:30:49;;5970:50;;;6016:1;6013;6006:12;5970:50;6053:4;6045:6;6041:17;6029:29;;6113:3;6106:4;6096:6;6093:1;6089:14;6081:6;6077:27;6073:38;6070:47;6067:67;;;6130:1;6127;6120:12;6067:67;5773:367;;;;;:::o;6145:1099::-;6303:6;6311;6319;6327;6335;6343;6396:2;6384:9;6375:7;6371:23;6367:32;6364:52;;;6412:1;6409;6402:12;6364:52;6439:23;;-1:-1:-1;;;;;6474:30:49;;6471:50;;;6517:1;6514;6507:12;6471:50;6556:70;6618:7;6609:6;6598:9;6594:22;6556:70;:::i;:::-;6645:8;;-1:-1:-1;6530:96:49;-1:-1:-1;;6733:2:49;6718:18;;6705:32;-1:-1:-1;;;;;6749:32:49;;6746:52;;;6794:1;6791;6784:12;6746:52;6833:72;6897:7;6886:8;6875:9;6871:24;6833:72;:::i;:::-;6924:8;;-1:-1:-1;6807:98:49;-1:-1:-1;;7012:2:49;6997:18;;6984:32;-1:-1:-1;;;;;7028:32:49;;7025:52;;;7073:1;7070;7063:12;7025:52;7112:72;7176:7;7165:8;7154:9;7150:24;7112:72;:::i;:::-;6145:1099;;;;-1:-1:-1;6145:1099:49;;-1:-1:-1;6145:1099:49;;7203:8;;6145:1099;-1:-1:-1;;;6145:1099:49:o;7249:844::-;7352:6;7360;7368;7376;7384;7392;7445:3;7433:9;7424:7;7420:23;7416:33;7413:53;;;7462:1;7459;7452:12;7413:53;7501:9;7488:23;7520:31;7545:5;7520:31;:::i;:::-;7570:5;-1:-1:-1;7594:37:49;7627:2;7612:18;;7594:37;:::i;:::-;7584:47;;7683:2;7672:9;7668:18;7655:32;7696:33;7721:7;7696:33;:::i;:::-;7748:7;-1:-1:-1;7828:2:49;7813:18;;7800:32;;-1:-1:-1;7910:3:49;7895:19;;7882:33;7924;7882;7924;:::i;:::-;7249:844;;;;-1:-1:-1;7249:844:49;;;;;8056:3;8041:19;;;8028:33;;-1:-1:-1;;7249:844:49:o;8098:418::-;8174:6;8182;8190;8243:2;8231:9;8222:7;8218:23;8214:32;8211:52;;;8259:1;8256;8249:12;8211:52;8282:28;8300:9;8282:28;:::i;:::-;8272:38;8379:2;8364:18;;8351:32;;-1:-1:-1;8480:2:49;8465:18;;;8452:32;;8098:418;-1:-1:-1;;;8098:418:49:o;8521:682::-;8691:4;8739:2;8728:9;8724:18;8769:6;8758:9;8751:25;8812:2;8807;8796:9;8792:18;8785:30;8835:6;8870;8864:13;8901:6;8893;8886:22;8939:2;8928:9;8924:18;8917:25;;8977:2;8969:6;8965:15;8951:29;;8998:1;9008:169;9022:6;9019:1;9016:13;9008:169;;;9083:13;;9071:26;;9126:2;9152:15;;;;9117:12;;;;9044:1;9037:9;9008:169;;;-1:-1:-1;9194:3:49;;8521:682;-1:-1:-1;;;;;;8521:682:49:o;9208:465::-;9465:2;9454:9;9447:21;9428:4;9491:56;9543:2;9532:9;9528:18;9520:6;9491:56;:::i;:::-;9595:9;9587:6;9583:22;9578:2;9567:9;9563:18;9556:50;9623:44;9660:6;9652;9623:44;:::i;9678:460::-;9754:6;9762;9770;9823:2;9811:9;9802:7;9798:23;9794:32;9791:52;;;9839:1;9836;9829:12;9791:52;9878:9;9865:23;9897:31;9922:5;9897:31;:::i;:::-;9947:5;-1:-1:-1;10004:2:49;9989:18;;9976:32;10017:33;9976:32;10017:33;:::i;:::-;10069:7;-1:-1:-1;10095:37:49;10128:2;10113:18;;10095:37;:::i;:::-;10085:47;;9678:460;;;;;:::o;10143:393::-;10235:6;10288:2;10276:9;10267:7;10263:23;10259:32;10256:52;;;10304:1;10301;10294:12;10256:52;10331:23;;-1:-1:-1;;;;;10366:30:49;;10363:50;;;10409:1;10406;10399:12;10363:50;10432:22;;10488:3;10470:16;;;10466:26;10463:46;;;10505:1;10502;10495:12;10541:346;10609:6;10617;10670:2;10658:9;10649:7;10645:23;10641:32;10638:52;;;10686:1;10683;10676:12;10638:52;-1:-1:-1;;10731:23:49;;;10851:2;10836:18;;;10823:32;;-1:-1:-1;10541:346:49:o;10892:319::-;10959:6;10967;11020:2;11008:9;10999:7;10995:23;10991:32;10988:52;;;11036:1;11033;11026:12;10988:52;11075:9;11062:23;11094:31;11119:5;11094:31;:::i;:::-;11144:5;-1:-1:-1;11168:37:49;11201:2;11186:18;;11168:37;:::i;:::-;11158:47;;10892:319;;;;;:::o;12065:444::-;12117:3;12155:5;12149:12;12182:6;12177:3;12170:19;12214:4;12209:3;12205:14;12198:21;;12253:4;12246:5;12242:16;12276:1;12286:198;12300:6;12297:1;12294:13;12286:198;;;12365:13;;-1:-1:-1;;;;;12361:38:49;12349:51;;12429:4;12420:14;;;;12457:17;;;;12396:1;12315:9;12286:198;;12514:258;12691:2;12680:9;12673:21;12654:4;12711:55;12762:2;12751:9;12747:18;12739:6;12711:55;:::i;12777:154::-;12836:5;12881:2;12872:6;12867:3;12863:16;12859:25;12856:45;;;12897:1;12894;12887:12;12856:45;-1:-1:-1;12919:6:49;12777:154;-1:-1:-1;12777:154:49:o;12936:434::-;13064:6;13072;13080;13133:3;13121:9;13112:7;13108:23;13104:33;13101:53;;;13150:1;13147;13140:12;13101:53;13173:28;13191:9;13173:28;:::i;:::-;13163:38;;13220:62;13274:7;13269:2;13258:9;13254:18;13220:62;:::i;:::-;13210:72;;13301:63;13356:7;13350:3;13339:9;13335:19;13301:63;:::i;13375:1049::-;13505:6;13513;13521;13529;13537;13545;13553;13606:3;13594:9;13585:7;13581:23;13577:33;13574:53;;;13623:1;13620;13613:12;13574:53;13662:9;13649:23;13681:31;13706:5;13681:31;:::i;:::-;13731:5;-1:-1:-1;13755:37:49;13788:2;13773:18;;13755:37;:::i;:::-;13745:47;;13844:2;13833:9;13829:18;13816:32;13857:33;13882:7;13857:33;:::i;:::-;13909:7;-1:-1:-1;13967:2:49;13952:18;;13939:32;-1:-1:-1;;;;;13983:30:49;;13980:50;;;14026:1;14023;14016:12;13980:50;14065:70;14127:7;14118:6;14107:9;14103:22;14065:70;:::i;:::-;14154:8;;-1:-1:-1;14039:96:49;-1:-1:-1;;14241:3:49;14226:19;;14213:33;14255;14213;14255;:::i;:::-;13375:1049;;;;-1:-1:-1;13375:1049:49;;;;;;;;-1:-1:-1;;14387:3:49;14372:19;;;14359:33;;13375:1049::o;14429:462::-;14684:2;14673:9;14666:21;14647:4;14710:55;14761:2;14750:9;14746:18;14738:6;14710:55;:::i;15116:200::-;-1:-1:-1;;;;;15278:31:49;;;;15260:50;;15248:2;15233:18;;15116:200::o;15321:127::-;15382:10;15377:3;15373:20;15370:1;15363:31;15413:4;15410:1;15403:15;15437:4;15434:1;15427:15;15453:138;15532:13;;15554:31;15532:13;15554:31;:::i;15596:251::-;15666:6;15719:2;15707:9;15698:7;15694:23;15690:32;15687:52;;;15735:1;15732;15725:12;15687:52;15767:9;15761:16;15786:31;15811:5;15786:31;:::i;15852:127::-;15913:10;15908:3;15904:20;15901:1;15894:31;15944:4;15941:1;15934:15;15968:4;15965:1;15958:15;15984:252;16056:2;16050:9;16098:3;16086:16;;-1:-1:-1;;;;;16117:34:49;;16153:22;;;16114:62;16111:88;;;16179:18;;:::i;:::-;16215:2;16208:22;15984:252;:::o;16241:253::-;16313:2;16307:9;16355:4;16343:17;;-1:-1:-1;;;;;16375:34:49;;16411:22;;;16372:62;16369:88;;;16437:18;;:::i;16499:275::-;16570:2;16564:9;16635:2;16616:13;;-1:-1:-1;;16612:27:49;16600:40;;-1:-1:-1;;;;;16655:34:49;;16691:22;;;16652:62;16649:88;;;16717:18;;:::i;:::-;16753:2;16746:22;16499:275;;-1:-1:-1;16499:275:49:o;16779:163::-;16857:13;;16910:6;16899:18;;16889:29;;16879:57;;16932:1;16929;16922:12;16947:167;17025:13;;17078:10;17067:22;;17057:33;;17047:61;;17104:1;17101;17094:12;17119:132;17195:13;;17217:28;17195:13;17217:28;:::i;17256:1339::-;17357:6;17417:3;17405:9;17396:7;17392:23;17388:33;17433:2;17430:22;;;17448:1;17445;17438:12;17430:22;-1:-1:-1;17490:22:49;;:::i;:::-;17535:40;17565:9;17535:40;:::i;:::-;17528:5;17521:55;17608:48;17652:2;17641:9;17637:18;17608:48;:::i;:::-;17603:2;17596:5;17592:14;17585:72;17689:48;17733:2;17722:9;17718:18;17689:48;:::i;:::-;17684:2;17677:5;17673:14;17666:72;17770:48;17814:2;17803:9;17799:18;17770:48;:::i;:::-;17765:2;17758:5;17754:14;17747:72;17852:49;17896:3;17885:9;17881:19;17852:49;:::i;:::-;17846:3;17839:5;17835:15;17828:74;17935:49;17979:3;17968:9;17964:19;17935:49;:::i;:::-;17929:3;17922:5;17918:15;17911:74;18018:49;18062:3;18051:9;18047:19;18018:49;:::i;:::-;18012:3;18005:5;18001:15;17994:74;18101:50;18146:3;18135:9;18131:19;18101:50;:::i;:::-;18095:3;18088:5;18084:15;18077:75;18185:49;18229:3;18218:9;18214:19;18185:49;:::i;:::-;18179:3;18172:5;18168:15;18161:74;18268:49;18312:3;18301:9;18297:19;18268:49;:::i;:::-;18262:3;18255:5;18251:15;18244:74;18351:49;18395:3;18384:9;18380:19;18351:49;:::i;:::-;18345:3;18338:5;18334:15;18327:74;18434:49;18478:3;18467:9;18463:19;18434:49;:::i;:::-;18428:3;18421:5;18417:15;18410:74;18517:47;18559:3;18548:9;18544:19;18517:47;:::i;:::-;18511:3;18500:15;;18493:72;18504:5;17256:1339;-1:-1:-1;;;17256:1339:49:o;18600:183::-;18660:4;-1:-1:-1;;;;;18682:30:49;;18679:56;;;18715:18;;:::i;:::-;-1:-1:-1;18760:1:49;18756:14;18772:4;18752:25;;18600:183::o;18788:951::-;18883:6;18936:2;18924:9;18915:7;18911:23;18907:32;18904:52;;;18952:1;18949;18942:12;18904:52;18979:16;;-1:-1:-1;;;;;19007:30:49;;19004:50;;;19050:1;19047;19040:12;19004:50;19073:22;;19126:4;19118:13;;19114:27;-1:-1:-1;19104:55:49;;19155:1;19152;19145:12;19104:55;19188:2;19182:9;19211:64;19227:47;19267:6;19227:47;:::i;:::-;19211:64;:::i;:::-;19297:3;19321:6;19316:3;19309:19;19353:2;19348:3;19344:12;19337:19;;19408:2;19398:6;19395:1;19391:14;19387:2;19383:23;19379:32;19365:46;;19434:7;19426:6;19423:19;19420:39;;;19455:1;19452;19445:12;19420:39;19487:2;19483;19479:11;19468:22;;19499:210;19515:6;19510:3;19507:15;19499:210;;;19588:3;19582:10;19605:31;19630:5;19605:31;:::i;:::-;19649:18;;19696:2;19532:12;;;;19687;;;;19499:210;;19744:420;19797:3;19835:5;19829:12;19862:6;19857:3;19850:19;19894:4;19889:3;19885:14;19878:21;;19933:4;19926:5;19922:16;19956:1;19966:173;19980:6;19977:1;19974:13;19966:173;;;20041:13;;20029:26;;20084:4;20075:14;;;;20112:17;;;;20002:1;19995:9;19966:173;;20169:261;20348:2;20337:9;20330:21;20311:4;20368:56;20420:2;20409:9;20405:18;20397:6;20368:56;:::i;20435:782::-;20626:2;20608:21;;;20669:13;;-1:-1:-1;;;;;20665:39:49;;;20645:18;;;20638:67;20751:15;;;20745:22;-1:-1:-1;;;;;20741:47:49;20777:2;20721:18;;;20714:75;;;;20835:15;;20829:22;20825:48;;20820:2;20805:18;;;20798:76;;;;20921:15;;20915:22;20911:48;;20905:3;20890:19;;;20883:77;;;;21007:16;;21001:23;20997:49;20692:3;20976:19;;;20969:78;;;;21082:16;;21076:23;21137:4;21115:20;;;21108:34;-1:-1:-1;;21159:52:49;21206:3;21191:19;;21076:23;21159:52;:::i;21222:371::-;-1:-1:-1;;;;;21442:32:49;;;21424:51;;21511:32;;;;21506:2;21491:18;;21484:60;21575:2;21560:18;;21553:34;;;;21412:2;21397:18;;21222:371::o;21598:127::-;21659:10;21654:3;21650:20;21647:1;21640:31;21690:4;21687:1;21680:15;21714:4;21711:1;21704:15;21730:125;21795:9;;;21816:10;;;21813:36;;;21829:18;;:::i;21860:128::-;21927:9;;;21948:11;;;21945:37;;;21962:18;;:::i;21993:135::-;22032:3;22053:17;;;22050:43;;22073:18;;:::i;:::-;-1:-1:-1;22120:1:49;22109:13;;21993:135::o;22133:245::-;22200:6;22253:2;22241:9;22232:7;22228:23;22224:32;22221:52;;;22269:1;22266;22259:12;22221:52;22301:9;22295:16;22320:28;22342:5;22320:28;:::i;22597:521::-;22674:4;22680:6;22740:11;22727:25;22834:2;22830:7;22819:8;22803:14;22799:29;22795:43;22775:18;22771:68;22761:96;;22853:1;22850;22843:12;22761:96;22880:33;;22932:20;;;-1:-1:-1;;;;;;22964:30:49;;22961:50;;;23007:1;23004;22997:12;22961:50;23040:4;23028:17;;-1:-1:-1;23071:14:49;23067:27;;;23057:38;;23054:58;;;23108:1;23105;23098:12;23383:173;23451:20;;-1:-1:-1;;;;;23500:31:49;;23490:42;;23480:70;;23546:1;23543;23536:12;23561:702;23644:6;23704:2;23692:9;23683:7;23679:23;23675:32;23719:2;23716:22;;;23734:1;23731;23724:12;23716:22;-1:-1:-1;23803:2:49;23797:9;23845:2;23833:15;;-1:-1:-1;;;;;23863:34:49;;23899:22;;;23860:62;23857:88;;;23925:18;;:::i;:::-;23961:2;23954:22;23998:23;;24030:28;23998:23;24030:28;:::i;:::-;24067:21;;24121:38;24155:2;24140:18;;24121:38;:::i;:::-;24116:2;24108:6;24104:15;24097:63;24193:38;24227:2;24216:9;24212:18;24193:38;:::i;:::-;24188:2;24176:15;;24169:63;24180:6;23561:702;-1:-1:-1;;;23561:702:49:o;24268:300::-;-1:-1:-1;;;;;24460:32:49;;;24442:51;;24529:32;;24524:2;24509:18;;24502:60;24430:2;24415:18;;24268:300::o;24573:1553::-;24818:1;24814;24810:2;24806:10;24802:18;24794:6;24790:31;24779:9;24772:50;24858:2;24853;24842:9;24838:18;24831:30;24753:4;24896:6;24890:13;24939:4;24934:2;24923:9;24919:18;24912:32;24967:52;25014:3;25003:9;24999:19;24985:12;24967:52;:::i;:::-;24953:66;;25068:2;25060:6;25056:15;25050:22;25140:2;25136:7;25124:9;25116:6;25112:22;25108:36;25103:2;25092:9;25088:18;25081:64;25168:41;25202:6;25186:14;25168:41;:::i;:::-;25258:2;25246:15;;25240:22;25303;;;-1:-1:-1;;25299:36:49;25293:3;25278:19;;25271:65;25385:21;;25415:22;;;25465:2;25491:23;;;;-1:-1:-1;25532:1:49;;-1:-1:-1;25453:15:49;;;25542:280;25556:6;25553:1;25550:13;25542:280;;;25615:13;;25657:9;;-1:-1:-1;;;;;25653:35:49;25641:48;;25737:2;25729:11;;;25723:18;25709:12;;;25702:40;25797:15;;;;25685:1;25571:9;;;;;25771:2;25762:12;;;;25542:280;;;-1:-1:-1;25871:2:49;25859:15;;25853:22;-1:-1:-1;;;;;1965:31:49;25934:4;25919:20;;1953:44;25989:3;25977:16;;25971:23;26035:19;;;-1:-1:-1;;26031:33:49;26025:3;26010:19;;26003:62;25971:23;-1:-1:-1;26082:38:49;26035:19;25971:23;26082:38;:::i;26131:230::-;26201:6;26254:2;26242:9;26233:7;26229:23;26225:32;26222:52;;;26270:1;26267;26260:12;26222:52;-1:-1:-1;26315:16:49;;26131:230;-1:-1:-1;26131:230:49:o;27134:558::-;27176:5;27229:3;27222:4;27214:6;27210:17;27206:27;27196:55;;27247:1;27244;27237:12;27196:55;27274:20;;-1:-1:-1;;;;;27306:30:49;;27303:56;;;27339:18;;:::i;:::-;27383:59;27430:2;27407:17;;-1:-1:-1;;27403:31:49;27436:4;27399:42;27383:59;:::i;:::-;27467:6;27458:7;27451:23;27521:3;27514:4;27505:6;27497;27493:19;27489:30;27486:39;27483:59;;;27538:1;27535;27528:12;27483:59;27603:6;27596:4;27588:6;27584:17;27577:4;27568:7;27564:18;27551:59;27659:1;27630:20;;;27652:4;27626:31;27619:42;;;;27634:7;27134:558;-1:-1:-1;;;27134:558:49:o;27697:1133::-;27787:6;27840:2;27828:9;27819:7;27815:23;27811:32;27808:52;;;27856:1;27853;27846:12;27808:52;27883:23;;-1:-1:-1;;;;;27918:30:49;;27915:50;;;27961:1;27958;27951:12;27915:50;27984:22;;28040:4;28022:16;;;28018:27;28015:47;;;28058:1;28055;28048:12;28015:47;28084:22;;:::i;:::-;28143:2;28130:16;28155:33;28180:7;28155:33;:::i;:::-;28197:22;;28251:30;28277:2;28269:11;;28251:30;:::i;:::-;28246:2;28239:5;28235:14;28228:54;28327:2;28323;28319:11;28306:25;28340:33;28365:7;28340:33;:::i;:::-;28400:2;28389:14;;28382:31;28458:2;28450:11;;28437:25;28471:33;28437:25;28471:33;:::i;:::-;28531:2;28520:14;;28513:31;28577:32;28604:3;28596:12;;28577:32;:::i;:::-;28571:3;28560:15;;28553:57;28656:3;28648:12;;28635:26;-1:-1:-1;;;;;28673:32:49;;28670:52;;;28718:1;28715;28708:12;28670:52;28755:44;28791:7;28780:8;28776:2;28772:17;28755:44;:::i;:::-;28749:3;28738:15;;28731:69;-1:-1:-1;28742:5:49;27697:1133;-1:-1:-1;;;;27697:1133:49:o;29134:930::-;29229:6;29282:2;29270:9;29261:7;29257:23;29253:32;29250:52;;;29298:1;29295;29288:12;29250:52;29325:16;;-1:-1:-1;;;;;29353:30:49;;29350:50;;;29396:1;29393;29386:12;29350:50;29419:22;;29472:4;29464:13;;29460:27;-1:-1:-1;29450:55:49;;29501:1;29498;29491:12;29450:55;29534:2;29528:9;29557:64;29573:47;29613:6;29573:47;:::i;29557:64::-;29643:3;29667:6;29662:3;29655:19;29699:2;29694:3;29690:12;29683:19;;29754:2;29744:6;29741:1;29737:14;29733:2;29729:23;29725:32;29711:46;;29780:7;29772:6;29769:19;29766:39;;;29801:1;29798;29791:12;29766:39;29833:2;29829;29825:11;29814:22;;29845:189;29861:6;29856:3;29853:15;29845:189;;;29951:10;;29974:18;;30021:2;29878:12;;;;30012;;;;29845:189;;30069:449;30300:2;30289:9;30282:21;30263:4;30320:56;30372:2;30361:9;30357:18;30349:6;30320:56;:::i;:::-;-1:-1:-1;;;;;30412:31:49;;;30407:2;30392:18;;30385:59;30480:31;;;;30432:2;30460:18;;;30453:59;30480:31;30312:64;-1:-1:-1;;30069:449:49:o;30825:271::-;30911:12;;30904:20;30897:28;30885:41;;30979:4;30968:16;;;30962:23;-1:-1:-1;;;;;30958:49:49;;;30942:14;;;30935:73;;;;31061:4;31050:16;;;31044:23;31040:49;31024:14;;31017:73;30825:271::o;31101:381::-;31359:3;31344:19;;31372:43;31348:9;31397:6;31372:43;:::i;:::-;31424:52;31472:2;31461:9;31457:18;31449:6;31424:52;:::i;31487:274::-;-1:-1:-1;;;;;31679:32:49;;;;31661:51;;31743:2;31728:18;;31721:34;31649:2;31634:18;;31487:274::o;33050:168::-;33123:9;;;33154;;33171:15;;;33165:22;;33151:37;33141:71;;33192:18;;:::i;33223:243::-;33405:2;33390:18;;33417:43;33394:9;33442:6;33417:43;:::i;33471:127::-;33532:10;33527:3;33523:20;33520:1;33513:31;33563:4;33560:1;33553:15;33587:4;33584:1;33577:15;33603:345;33805:25;;;33861:2;33846:18;;33839:34;;;;-1:-1:-1;;;;;33909:32:49;33904:2;33889:18;;33882:60;33793:2;33778:18;;33603:345::o;33953:217::-;33993:1;34019;34009:132;;34063:10;34058:3;34054:20;34051:1;34044:31;34098:4;34095:1;34088:15;34126:4;34123:1;34116:15;34009:132;-1:-1:-1;34155:9:49;;33953:217::o;34175:301::-;34304:3;34342:6;34336:13;34388:6;34381:4;34373:6;34369:17;34364:3;34358:37;34450:1;34414:16;;34439:13;;;-1:-1:-1;34414:16:49;34175:301;-1:-1:-1;34175:301:49:o
Swarm Source
ipfs://bba0137ca3101440e2b76765b14e4154ddbde848a7797d09aa47ff6d4820a230
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.