Source Code
Overview
GLMR Balance
GLMR Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 6757285 | 546 days ago | 0 GLMR | ||||
| 5992847 | 643 days ago | 0 GLMR | ||||
| 5411037 | 725 days ago | 0 GLMR | ||||
| 5169681 | 759 days ago | 0 GLMR | ||||
| 5169681 | 759 days ago | 0 GLMR | ||||
| 5169681 | 759 days ago | 0 GLMR | ||||
| 5169681 | 759 days ago | 0 GLMR | ||||
| 5169681 | 759 days ago | 0 GLMR | ||||
| 5169681 | 759 days ago | 0 GLMR | ||||
| 5169676 | 759 days ago | 0 GLMR | ||||
| 5086179 | 771 days ago | 0 GLMR | ||||
| 5086179 | 771 days ago | 0 GLMR | ||||
| 5086179 | 771 days ago | 0 GLMR | ||||
| 5086179 | 771 days ago | 0 GLMR | ||||
| 5086179 | 771 days ago | 0 GLMR | ||||
| 5086179 | 771 days ago | 0 GLMR | ||||
| 5086176 | 771 days ago | 0 GLMR | ||||
| 5086175 | 771 days ago | 0 GLMR | ||||
| 5086175 | 771 days ago | 0 GLMR | ||||
| 5086175 | 771 days ago | 0 GLMR | ||||
| 5086175 | 771 days ago | 0 GLMR | ||||
| 5086175 | 771 days ago | 0 GLMR | ||||
| 5086175 | 771 days ago | 0 GLMR | ||||
| 5086174 | 771 days ago | 0 GLMR | ||||
| 5086174 | 771 days ago | 0 GLMR |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
NFTBridgeImplementation
Compiler Version
v0.8.14+commit.80d49f37
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
import "./NFTBridge.sol";
contract NFTBridgeImplementation is NFTBridge {
// Beacon getter for the token contracts
function implementation() public view returns (address) {
return tokenImplementation();
}
function initialize() initializer public virtual {
// this function needs to be exposed for an upgrade to pass
}
modifier initializer() {
address impl = ERC1967Upgrade._getImplementation();
require(
!isInitialized(impl),
"already initialized"
);
_setInitialized(impl);
_;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967Upgrade {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../libraries/external/BytesLib.sol";
import "./NFTBridgeGetters.sol";
import "./NFTBridgeSetters.sol";
import "./NFTBridgeStructs.sol";
import "./NFTBridgeGovernance.sol";
import "./token/NFT.sol";
import "./token/NFTImplementation.sol";
import "../interfaces/IZKBridgeReceiver.sol";
contract NFTBridge is NFTBridgeGovernance, IZKBridgeReceiver, ReentrancyGuard {
using BytesLib for bytes;
event TransferNFT(uint64 indexed sequence, address token, uint256 tokenID, uint16 recipientChain, address sender, address recipient);
event ReceiveNFT(uint64 indexed sequence, address sourceToken, address token, uint256 tokenID, uint16 sourceChain, uint16 sendChain, address recipient);
function transferNFT(address token, uint256 tokenID, uint16 recipientChain, bytes32 recipient) public payable nonReentrant returns (uint64 sequence) {
// determine token parameters
uint16 tokenChain;
bytes32 tokenAddress;
if (isWrappedAsset(token)) {
tokenChain = NFTImplementation(token).chainId();
tokenAddress = NFTImplementation(token).nativeContract();
} else {
tokenChain = chainId();
tokenAddress = bytes32(uint256(uint160(token)));
// Verify that the correct interfaces are implemented
require(ERC165(token).supportsInterface(type(IERC721).interfaceId), "must support the ERC721 interface");
require(ERC165(token).supportsInterface(type(IERC721Metadata).interfaceId), "must support the ERC721-Metadata extension");
}
string memory symbolString;
string memory nameString;
string memory uriString;
{
(,bytes memory queriedSymbol) = token.staticcall(abi.encodeWithSignature("symbol()"));
(,bytes memory queriedName) = token.staticcall(abi.encodeWithSignature("name()"));
symbolString = abi.decode(queriedSymbol, (string));
nameString = abi.decode(queriedName, (string));
(,bytes memory queriedURI) = token.staticcall(abi.encodeWithSignature("tokenURI(uint256)", tokenID));
uriString = abi.decode(queriedURI, (string));
}
bytes32 symbol;
bytes32 name;
assembly {
// first 32 bytes hold string length
// mload then loads the next word, i.e. the first 32 bytes of the strings
// NOTE: this means that we might end up with an
// invalid utf8 string (e.g. if we slice an emoji in half). The VAA
// payload specification doesn't require that these are valid utf8
// strings, and it's cheaper to do any validation off-chain for
// presentation purposes
symbol := mload(add(symbolString, 32))
name := mload(add(nameString, 32))
}
IERC721(token).safeTransferFrom(msg.sender, address(this), tokenID);
if (tokenChain != chainId()) {
NFTImplementation(token).burn(tokenID);
}
sequence = logTransfer(NFTBridgeStructs.Transfer({
tokenAddress : tokenAddress,
tokenChain : tokenChain,
name : name,
symbol : symbol,
tokenID : tokenID,
uri : uriString,
to : recipient,
toChain : recipientChain
}), msg.value);
emit TransferNFT(sequence, token, tokenID, recipientChain, msg.sender, _truncateAddress(recipient));
}
function transferNFTBatch(address[] memory tokenList, uint256[] memory tokenIDList, uint16 recipientChain, bytes32 recipient) public payable nonReentrant returns (uint64 sequence) {
require(tokenList.length == tokenIDList.length, "length error");
bytes32[] memory tokenAddressList = new bytes32[](tokenList.length);
uint16[] memory tokenChainList = new uint16[](tokenList.length);
bytes32[] memory nameList = new bytes32[](tokenList.length);
bytes32[] memory symbolList = new bytes32[](tokenList.length);
string[] memory uriStringList = new string[](tokenList.length);
uint256[] memory tokenIDLists = new uint256[](tokenList.length);
for (uint256 i; i < tokenList.length; i++) {
address token = tokenList[i];
uint256 tokenID = tokenIDList[i];
uint16 tokenChain;
bytes32 tokenAddress;
if (isWrappedAsset(token)) {
tokenChain = NFTImplementation(token).chainId();
tokenAddress = NFTImplementation(token).nativeContract();
} else {
tokenChain = chainId();
tokenAddress = bytes32(uint256(uint160(token)));
// Verify that the correct interfaces are implemented
require(ERC165(token).supportsInterface(type(IERC721).interfaceId), "must support the ERC721 interface");
require(ERC165(token).supportsInterface(type(IERC721Metadata).interfaceId), "must support the ERC721-Metadata extension");
}
tokenAddressList[i] = tokenAddress;
string memory symbolString;
string memory nameString;
string memory uriString;
{
(,bytes memory queriedSymbol) = token.staticcall(abi.encodeWithSignature("symbol()"));
(,bytes memory queriedName) = token.staticcall(abi.encodeWithSignature("name()"));
symbolString = abi.decode(queriedSymbol, (string));
nameString = abi.decode(queriedName, (string));
(,bytes memory queriedURI) = token.staticcall(abi.encodeWithSignature("tokenURI(uint256)", tokenID));
uriString = abi.decode(queriedURI, (string));
}
bytes32 symbol;
bytes32 name;
assembly {
// first 32 bytes hold string length
// mload then loads the next word, i.e. the first 32 bytes of the strings
// NOTE: this means that we might end up with an
// invalid utf8 string (e.g. if we slice an emoji in half). The VAA
// payload specification doesn't require that these are valid utf8
// strings, and it's cheaper to do any validation off-chain for
// presentation purposes
symbol := mload(add(symbolString, 32))
name := mload(add(nameString, 32))
}
IERC721(token).safeTransferFrom(msg.sender, address(this), tokenID);
if (tokenChain != chainId()) {
NFTImplementation(token).burn(tokenID);
}
tokenChainList[i] = tokenChain;
nameList[i] = name;
symbolList[i] = symbol;
uriStringList[i] = uriString;
tokenIDLists[i] = tokenID;
}
sequence = logTransferBatch(NFTBridgeStructs.TransferBatch({
tokenAddress : tokenAddressList,
tokenChain : tokenChainList,
name : nameList,
symbol : symbolList,
tokenID : tokenIDLists,
uri : uriStringList,
to : recipient,
toChain : recipientChain
}), msg.value);
for (uint256 i = 0; i < tokenList.length; i++) {
emit TransferNFT(sequence, tokenList[i], tokenIDList[i], recipientChain, msg.sender, _truncateAddress(recipient));
}
}
function logTransfer(NFTBridgeStructs.Transfer memory transfer, uint256 callValue) internal returns (uint64 sequence) {
bytes memory encoded = encodeTransfer(transfer);
address dstContractAddress = bridgeContracts(transfer.toChain);
sequence = zkBridge().send{value : callValue}(transfer.toChain, dstContractAddress, encoded);
}
function logTransferBatch(NFTBridgeStructs.TransferBatch memory transfer, uint256 callValue) internal returns (uint64 sequence) {
for (uint256 i = 0; i < transfer.uri.length; i++) {
require(bytes(transfer.uri[i]).length <= 200, "tokenURI must not exceed 200 bytes");
}
bytes memory encoded = abi.encode(
transfer.tokenAddress,
transfer.tokenChain,
transfer.symbol,
transfer.name,
transfer.tokenID,
transfer.uri,
transfer.to,
transfer.toChain
);
address dstAddress = bridgeContracts(transfer.toChain);
sequence = zkBridge().send{value : callValue}(transfer.toChain, dstAddress, encoded);
}
function zkReceive(uint16 srcChainId, address srcAddress, uint64 sequence, bytes calldata payload) external nonReentrant override {
require(msg.sender == address(zkBridge()), "Not From ZKBridgeEntrypoint");
require(bridgeContracts(srcChainId) == srcAddress, "invalid emitter");
uint8 payloadID = payload.toUint8(0);
if (payloadID == 1) {
_completeTransfer(srcChainId, sequence, payload);
} else {
_completeTransferBatch(srcChainId, sequence, payload);
}
}
function _completeTransfer(uint16 srcChainId, uint64 sequence, bytes calldata payload) internal {
NFTBridgeStructs.Transfer memory transfer = parseTransfer(payload);
require(transfer.toChain == chainId(), "invalid target chain");
IERC721 transferToken;
if (transfer.tokenChain == chainId()) {
transferToken = IERC721(_truncateAddress(transfer.tokenAddress));
} else {
address wrapped = wrappedAsset(transfer.tokenChain, transfer.tokenAddress);
// If the wrapped asset does not exist yet, create it
if (wrapped == address(0)) {
wrapped = _createWrapped(transfer.tokenChain, transfer.tokenAddress, transfer.name, transfer.symbol);
}
transferToken = IERC721(wrapped);
}
// transfer bridged NFT to recipient
address transferRecipient = _truncateAddress(transfer.to);
if (transfer.tokenChain != chainId()) {
// mint wrapped asset
NFTImplementation(address(transferToken)).mint(transferRecipient, transfer.tokenID, transfer.uri);
} else {
transferToken.safeTransferFrom(address(this), transferRecipient, transfer.tokenID);
}
emit ReceiveNFT(sequence, _truncateAddress(transfer.tokenAddress), address(transferToken), transfer.tokenID, transfer.tokenChain, srcChainId, transferRecipient);
}
function _completeTransferBatch(uint16 srcChainId, uint64 sequence, bytes calldata payload) internal {
NFTBridgeStructs.TransferBatch memory transfer = parseTransferBatch(payload);
require(transfer.toChain == chainId(), "invalid target chain");
for (uint256 i = 0; i < transfer.tokenAddress.length; i++) {
IERC721 transferToken;
if (transfer.tokenChain[i] == chainId()) {
transferToken = IERC721(_truncateAddress(transfer.tokenAddress[i]));
} else {
address wrapped = wrappedAsset(transfer.tokenChain[i], transfer.tokenAddress[i]);
// If the wrapped asset does not exist yet, create it
if (wrapped == address(0)) {
wrapped = _createWrapped(transfer.tokenChain[i], transfer.tokenAddress[i], transfer.name[i], transfer.symbol[i]);
}
transferToken = IERC721(wrapped);
}
// transfer bridged NFT to recipient
address transferRecipient = _truncateAddress(transfer.to);
if (transfer.tokenChain[i] != chainId()) {
// mint wrapped asset
NFTImplementation(address(transferToken)).mint(transferRecipient, transfer.tokenID[i], transfer.uri[i]);
} else {
transferToken.safeTransferFrom(address(this), transferRecipient, transfer.tokenID[i]);
}
emit ReceiveNFT(sequence, _truncateAddress(transfer.tokenAddress[i]), address(transferToken), transfer.tokenID[i], transfer.tokenChain[i], srcChainId, transferRecipient);
}
}
// Creates a wrapped asset using AssetMeta
function _createWrapped(uint16 tokenChain, bytes32 tokenAddress, bytes32 name, bytes32 symbol) internal returns (address token) {
require(tokenChain != chainId(), "can only wrap tokens from foreign chains");
require(wrappedAsset(tokenChain, tokenAddress) == address(0), "wrapped asset already exists");
// initialize the NFTImplementation
bytes memory initialisationArgs = abi.encodeWithSelector(
NFTImplementation.initialize.selector,
bytes32ToString(name),
bytes32ToString(symbol),
address(this),
tokenChain,
tokenAddress
);
// initialize the BeaconProxy
bytes memory constructorArgs = abi.encode(address(this), initialisationArgs);
// deployment code
bytes memory bytecode = abi.encodePacked(type(BridgeNFT).creationCode, constructorArgs);
bytes32 salt = keccak256(abi.encodePacked(tokenChain, tokenAddress));
assembly {
token := create2(0, add(bytecode, 0x20), mload(bytecode), salt)
if iszero(extcodesize(token)) {
revert(0, 0)
}
}
_setWrappedAsset(tokenChain, tokenAddress, token);
}
function encodeTransfer(NFTBridgeStructs.Transfer memory transfer) internal pure returns (bytes memory encoded) {
// There is a global limit on 200 bytes of tokenURI in ZkBridge due to Solana
require(bytes(transfer.uri).length <= 200, "tokenURI must not exceed 200 bytes");
encoded = abi.encodePacked(
uint8(1),
transfer.tokenAddress,
transfer.tokenChain,
transfer.symbol,
transfer.name,
transfer.tokenID,
uint8(bytes(transfer.uri).length),
transfer.uri,
transfer.to,
transfer.toChain
);
}
function parseTransfer(bytes memory encoded) internal pure returns (NFTBridgeStructs.Transfer memory transfer) {
uint index = 0;
uint8 payloadID = encoded.toUint8(index);
index += 1;
require(payloadID == 1, "invalid Transfer");
transfer.tokenAddress = encoded.toBytes32(index);
index += 32;
transfer.tokenChain = encoded.toUint16(index);
index += 2;
transfer.symbol = encoded.toBytes32(index);
index += 32;
transfer.name = encoded.toBytes32(index);
index += 32;
transfer.tokenID = encoded.toUint256(index);
index += 32;
// Ignore length due to malformatted payload
index += 1;
transfer.uri = string(encoded.slice(index, encoded.length - index - 34));
// From here we read backwards due malformatted package
index = encoded.length;
index -= 2;
transfer.toChain = encoded.toUint16(index);
index -= 32;
transfer.to = encoded.toBytes32(index);
//require(encoded.length == index, "invalid Transfer");
}
function parseTransferBatch(bytes memory encoded) internal pure returns (NFTBridgeStructs.TransferBatch memory transfer) {
(transfer.tokenAddress,
transfer.tokenChain,
transfer.symbol,
transfer.name,
transfer.tokenID,
transfer.uri,
transfer.to,
transfer.toChain) = abi.decode(encoded, (bytes32[], uint16[], bytes32[], bytes32[], uint256[], string[], bytes32, uint16));
}
/*
* @dev Truncate a 32 byte array to a 20 byte address.
* Reverts if the array contains non-0 bytes in the first 12 bytes.
*
* @param bytes32 bytes The 32 byte array to be converted.
*/
function _truncateAddress(bytes32 b) internal pure returns (address) {
require(bytes12(b) == 0, "invalid EVM address");
return address(uint160(uint256(b)));
}
function onERC721Received(
address operator,
address,
uint256,
bytes calldata
) external view returns (bytes4){
require(operator == address(this), "can only bridge tokens via transferNFT method");
return type(IERC721Receiver).interfaceId;
}
function bytes32ToString(bytes32 input) internal pure returns (string memory) {
uint256 i;
while (i < 32 && input[i] != 0) {
i++;
}
bytes memory array = new bytes(i);
for (uint c = 0; c < i; c++) {
array[c] = input[c];
}
return string(array);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../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: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* 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 caller.
*
* 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: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IZKBridge.sol";
import "./NFTBridgeState.sol";
contract NFTBridgeGetters is NFTBridgeState {
function isInitialized(address impl) public view returns (bool) {
return _state.initializedImplementations[impl];
}
function zkBridge() public view returns (IZKBridge) {
return IZKBridge(_state.zkBridge);
}
function chainId() public view returns (uint16){
return _state.provider.chainId;
}
function wrappedAsset(uint16 tokenChainId, bytes32 tokenAddress) public view returns (address){
return _state.wrappedAssets[tokenChainId][tokenAddress];
}
function bridgeContracts(uint16 chainId_) public view returns (address){
return _state.bridgeImplementations[chainId_];
}
function tokenImplementation() public view returns (address){
return _state.tokenImplementation;
}
function isWrappedAsset(address token) public view returns (bool){
return _state.isWrappedAsset[token];
}
function owner() public view returns (address) {
return _state.owner;
}
function pendingImplementation() public view returns (address) {
return _state.pendingImplementation;
}
function toUpdateTime() public view returns (uint256) {
return _state.toUpdateTime;
}
function lockTime() public view returns (uint256) {
return _state.lockTime;
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./NFTBridgeState.sol";
contract NFTBridgeSetters is NFTBridgeState {
function _setInitialized(address implementation) internal {
_state.initializedImplementations[implementation] = true;
}
function _setChainId(uint16 chainId) internal {
_state.provider.chainId = chainId;
}
function _setBridgeImplementation(uint16 chainId, address bridgeContract) internal {
_state.bridgeImplementations[chainId] = bridgeContract;
}
function _setTokenImplementation(address impl) internal {
_state.tokenImplementation = impl;
}
function _setZKBridge(address h) internal {
_state.zkBridge = payable(h);
}
function _setWrappedAsset(uint16 tokenChainId, bytes32 tokenAddress, address wrapper) internal {
_state.wrappedAssets[tokenChainId][tokenAddress] = wrapper;
_state.isWrappedAsset[wrapper] = true;
}
function _setOwner(address owner) internal {
_state.owner = owner;
}
function _setPendingImplementation(address pendingImplementation) internal {
_state.pendingImplementation = pendingImplementation;
}
function _setToUpdateTime(uint256 toUpdateTime) internal {
_state.toUpdateTime = toUpdateTime;
}
function _setLockTime(uint256 lockTime) internal {
_state.lockTime = lockTime;
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
contract NFTBridgeStructs {
struct Transfer {
// PayloadID uint8 = 1
// Address of the token. Left-zero-padded if shorter than 32 bytes
bytes32 tokenAddress;
// Chain ID of the token
uint16 tokenChain;
// Symbol of the token
bytes32 symbol;
// Name of the token
bytes32 name;
// TokenID of the token
uint256 tokenID;
// URI of the token metadata (UTF-8)
string uri;
// Address of the recipient. Left-zero-padded if shorter than 32 bytes
bytes32 to;
// Chain ID of the recipient
uint16 toChain;
}
struct TransferBatch {
// PayloadID uint8 = 1
// Address of the token. Left-zero-padded if shorter than 32 bytes
bytes32[] tokenAddress;
// Chain ID of the token
uint16[] tokenChain;
// Symbol of the token
bytes32[] symbol;
// Name of the token
bytes32[] name;
// TokenID of the token
uint256[] tokenID;
// URI of the token metadata (UTF-8)
string[] uri;
// Address of the recipient. Left-zero-padded if shorter than 32 bytes
bytes32 to;
// Chain ID of the recipient
uint16 toChain;
}
struct RegisterChain {
// Governance Header
// module: "NFTBridge" left-padded
bytes32 module;
// governance action: 1
uint8 action;
// governance paket chain id: this or 0
uint16 chainId;
// Chain ID
uint16 emitterChainID;
// Emitter address. Left-zero-padded if shorter than 32 bytes
bytes32 emitterAddress;
}
struct UpgradeContract {
// Governance Header
// module: "NFTBridge" left-padded
bytes32 module;
// governance action: 2
uint8 action;
// governance paket chain id
uint16 chainId;
// Address of the new contract
bytes32 newContract;
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
import "../libraries/external/BytesLib.sol";
import "./NFTBridgeGetters.sol";
import "./NFTBridgeSetters.sol";
import "./NFTBridgeStructs.sol";
import "./token/NFT.sol";
import "./token/NFTImplementation.sol";
import "../interfaces/IZKBridge.sol";
contract NFTBridgeGovernance is NFTBridgeGetters, NFTBridgeSetters, ERC1967Upgrade {
event NewPendingImplementation(address indexed pendingImplementation, address indexed newImplementation);
event ContractUpgraded(address indexed oldContract, address indexed newContract);
event RegisterChain(uint16 chainId, address nftBridge);
modifier onlyOwner() {
require(owner() == msg.sender, "Ownable: caller is not the owner");
_;
}
function registerChain(uint16 chainId, address contractAddress) public onlyOwner {
_setBridgeImplementation(chainId, contractAddress);
emit RegisterChain(chainId, contractAddress);
}
function setLockTime(uint256 lockTime) public onlyOwner {
require(lockTime >= MIN_LOCK_TIME, 'Incorrect lockTime settings');
_setLockTime(lockTime);
}
function submitContractUpgrade(address newImplementation) public onlyOwner {
require(newImplementation != address(0), "Check pendingImplementation");
address currentPendingImplementation = pendingImplementation();
_setPendingImplementation(newImplementation);
_setToUpdateTime(block.timestamp + lockTime());
emit NewPendingImplementation(currentPendingImplementation, newImplementation);
}
function confirmContractUpgrade() public onlyOwner {
require(pendingImplementation() != address(0), "Check pendingImplementation");
require(block.timestamp >= toUpdateTime(), "Still locked in");
address currentImplementation = _getImplementation();
address newImplementation = pendingImplementation();
_setPendingImplementation(address(0));
_upgradeTo(newImplementation);
// Call initialize function of the new implementation
(bool success, bytes memory reason) = newImplementation.delegatecall(abi.encodeWithSignature("initialize()"));
require(success, string(reason));
emit ContractUpgraded(currentImplementation, newImplementation);
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
contract BridgeNFT is BeaconProxy {
constructor(address beacon, bytes memory data) BeaconProxy(beacon, data) {
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./NFTState.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
// Based on the OpenZepplin ERC721 implementation, licensed under MIT
contract NFTImplementation is NFTState, Context, IERC721, IERC721Metadata, ERC165 {
using Address for address;
using Strings for uint256;
function initialize(
string memory name_,
string memory symbol_,
address owner_,
uint16 chainId_,
bytes32 nativeContract_
) initializer public {
_state.name = name_;
_state.symbol = symbol_;
_state.owner = owner_;
_state.chainId = chainId_;
_state.nativeContract = nativeContract_;
}
function supportsInterface(bytes4 interfaceId) public view override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address owner_) public view override returns (uint256) {
require(owner_ != address(0), "ERC721: balance query for the zero address");
return _state.balances[owner_];
}
function ownerOf(uint256 tokenId) public view override returns (address) {
address owner_ = _state.owners[tokenId];
require(owner_ != address(0), "ERC721: owner query for nonexistent token");
return owner_;
}
function name() public view override returns (string memory) {
return _state.name;
}
function symbol() public view override returns (string memory) {
return _state.symbol;
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
return _state.tokenURIs[tokenId];
}
function chainId() public view returns (uint16) {
return _state.chainId;
}
function nativeContract() public view returns (bytes32) {
return _state.nativeContract;
}
function owner() public view returns (address) {
return _state.owner;
}
function approve(address to, uint256 tokenId) public override {
address owner_ = NFTImplementation.ownerOf(tokenId);
require(to != owner_, "ERC721: approval to current owner");
require(
_msgSender() == owner_ || isApprovedForAll(owner_, _msgSender()),
"ERC721: approve caller is not owner nor approved for all"
);
_approve(to, tokenId);
}
function getApproved(uint256 tokenId) public view override returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _state.tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public override {
require(operator != _msgSender(), "ERC721: approve to caller");
_state.operatorApprovals[_msgSender()][operator] = approved;
emit ApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(address owner_, address operator) public view override returns (bool) {
return _state.operatorApprovals[owner_][operator];
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public override {
//solhint-disable-next-line max-line-length
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public override {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransfer(from, to, tokenId, _data);
}
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory _data
) internal {
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
function _exists(uint256 tokenId) internal view returns (bool) {
return _state.owners[tokenId] != address(0);
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner_ = NFTImplementation.ownerOf(tokenId);
return (spender == owner_ || getApproved(tokenId) == spender || isApprovedForAll(owner_, spender));
}
function mint(address to, uint256 tokenId, string memory uri) public onlyOwner {
_mint(to, tokenId, uri);
}
function _mint(address to, uint256 tokenId, string memory uri) internal {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_state.balances[to] += 1;
_state.owners[tokenId] = to;
_state.tokenURIs[tokenId] = uri;
emit Transfer(address(0), to, tokenId);
}
function burn(uint256 tokenId) public onlyOwner {
_burn(tokenId);
}
function _burn(uint256 tokenId) internal {
address owner_ = NFTImplementation.ownerOf(tokenId);
// Clear approvals
_approve(address(0), tokenId);
_state.balances[owner_] -= 1;
delete _state.owners[tokenId];
emit Transfer(owner_, address(0), tokenId);
}
function _transfer(
address from,
address to,
uint256 tokenId
) internal {
require(NFTImplementation.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
// Clear approvals from the previous owner
_approve(address(0), tokenId);
_state.balances[from] -= 1;
_state.balances[to] += 1;
_state.owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function _approve(address to, uint256 tokenId) internal {
_state.tokenApprovals[tokenId] = to;
emit Approval(NFTImplementation.ownerOf(tokenId), to, tokenId);
}
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
modifier onlyOwner() {
require(owner() == _msgSender(), "caller is not the owner");
_;
}
modifier initializer() {
require(
!_state.initialized,
"Already initialized"
);
_state.initialized = true;
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IZKBridgeReceiver {
// @notice ZKBridge endpoint will invoke this function to deliver the message on the destination
// @param srcChainId - the source endpoint identifier
// @param srcAddress - the source sending contract address from the source chain
// @param sequence - the ordered message nonce
// @param payload - the signed payload is the UA bytes has encoded to be sent
function zkReceive(uint16 srcChainId, address srcAddress, uint64 sequence, bytes calldata payload) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.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
pragma solidity ^0.8.0;
interface IZKBridge {
function send(uint16 dstChainId, address dstAddress, bytes memory payload) external payable returns (uint64 sequence);
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "./NFTBridgeStructs.sol";
contract NFTBridgeStorage {
struct Provider {
uint16 chainId;
}
struct State {
address payable zkBridge;
address tokenImplementation;
address owner;
address pendingImplementation;
uint256 toUpdateTime;
uint256 lockTime;
// Mapping of initialized implementations
mapping(address => bool) initializedImplementations;
// Mapping of wrapped assets (chainID => nativeAddress => wrappedAddress)
mapping(uint16 => mapping(bytes32 => address)) wrappedAssets;
// Mapping to safely identify wrapped assets
mapping(address => bool) isWrappedAsset;
// Mapping of bridge contracts on other chains
mapping(uint16 => address) bridgeImplementations;
Provider provider;
}
}
contract NFTBridgeState {
NFTBridgeStorage.State _state;
uint256 public constant MIN_LOCK_TIME = 1 days;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol)
pragma solidity ^0.8.0;
import "./IBeacon.sol";
import "../Proxy.sol";
import "../ERC1967/ERC1967Upgrade.sol";
/**
* @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.
*
* The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't
* conflict with the storage layout of the implementation behind the proxy.
*
* _Available since v3.4._
*/
contract BeaconProxy is Proxy, ERC1967Upgrade {
/**
* @dev Initializes the proxy with `beacon`.
*
* If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
* will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity
* constructor.
*
* Requirements:
*
* - `beacon` must be a contract with the interface {IBeacon}.
*/
constructor(address beacon, bytes memory data) payable {
_upgradeBeaconToAndCall(beacon, data, false);
}
/**
* @dev Returns the current beacon address.
*/
function _beacon() internal view virtual returns (address) {
return _getBeacon();
}
/**
* @dev Returns the current implementation address of the associated beacon.
*/
function _implementation() internal view virtual override returns (address) {
return IBeacon(_getBeacon()).implementation();
}
/**
* @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.
*
* If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.
*
* Requirements:
*
* - `beacon` must be a contract.
* - The implementation returned by `beacon` must be a contract.
*/
function _setBeacon(address beacon, bytes memory data) internal virtual {
_upgradeBeaconToAndCall(beacon, data, false);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
pragma solidity ^0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive() external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overridden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
contract NFTStorage {
struct State {
// Token name
string name;
// Token symbol
string symbol;
// Mapping from token ID to owner address
mapping(uint256 => address) owners;
// Mapping owner address to token count
mapping(address => uint256) balances;
// Mapping from token ID to approved address
mapping(uint256 => address) tokenApprovals;
// Mapping from token ID to URI
mapping(uint256 => string) tokenURIs;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) operatorApprovals;
address owner;
bool initialized;
uint16 chainId;
bytes32 nativeContract;
}
}
contract NFTState {
NFTStorage.State _state;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldContract","type":"address"},{"indexed":true,"internalType":"address","name":"newContract","type":"address"}],"name":"ContractUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingImplementation","type":"address"},{"indexed":true,"internalType":"address","name":"newImplementation","type":"address"}],"name":"NewPendingImplementation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"sequence","type":"uint64"},{"indexed":false,"internalType":"address","name":"sourceToken","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"sourceChain","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"sendChain","type":"uint16"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"ReceiveNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"chainId","type":"uint16"},{"indexed":false,"internalType":"address","name":"nftBridge","type":"address"}],"name":"RegisterChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"sequence","type":"uint64"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"recipientChain","type":"uint16"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"TransferNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"MIN_LOCK_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"}],"name":"bridgeContracts","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"confirmContractUpgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"impl","type":"address"}],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isWrappedAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"contractAddress","type":"address"}],"name":"registerChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lockTime","type":"uint256"}],"name":"setLockTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"submitContractUpgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"uint16","name":"recipientChain","type":"uint16"},{"internalType":"bytes32","name":"recipient","type":"bytes32"}],"name":"transferNFT","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokenList","type":"address[]"},{"internalType":"uint256[]","name":"tokenIDList","type":"uint256[]"},{"internalType":"uint16","name":"recipientChain","type":"uint16"},{"internalType":"bytes32","name":"recipient","type":"bytes32"}],"name":"transferNFTBatch","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"tokenChainId","type":"uint16"},{"internalType":"bytes32","name":"tokenAddress","type":"bytes32"}],"name":"wrappedAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"zkBridge","outputs":[{"internalType":"contract IZKBridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcChainId","type":"uint16"},{"internalType":"address","name":"srcAddress","type":"address"},{"internalType":"uint64","name":"sequence","type":"uint64"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"zkReceive","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b506001600b556146aa806100256000396000f3fe6080604052600436106200014f5760003560e01c80638da5cb5b11620000b9578063ad66a5f11162000078578063ad66a5f114620003b1578063ae04d45d14620003ef578063b42446591462000414578063b6dc12361462000434578063d1dc83c21462000459578063d60b347f146200047157600080fd5b80638da5cb5b146200030e5780639a8a0592146200032e5780639f0a22a61462000353578063aba5ca04146200036a578063ac7b22dc146200039a57600080fd5b80632f3a3d5d11620001125780632f3a3d5d1462000260578063396f7b2314620002805780633a55275714620002a05780633ff0320714620002c55780635c60da1b14620002de5780638129fc1c14620002f657600080fd5b80630d6680871462000154578063150b7a0214620001795780631a2be4da14620001ad5780631ff1e28614620001fb5780632de9952a1462000239575b600080fd5b3480156200016157600080fd5b506005545b6040519081526020015b60405180910390f35b3480156200018657600080fd5b506200019e6200019836600462003029565b620004ae565b6040516200017091906200309f565b348015620001ba57600080fd5b50620001ea620001cc366004620030b4565b6001600160a01b031660009081526008602052604090205460ff1690565b604051901515815260200162000170565b3480156200020857600080fd5b50620002206200021a366004620030f7565b62000536565b6040516001600160a01b03909116815260200162000170565b3480156200024657600080fd5b506200025e620002583660046200313c565b62000562565b005b3480156200026d57600080fd5b506001546001600160a01b031662000220565b3480156200028d57600080fd5b506003546001600160a01b031662000220565b348015620002ad57600080fd5b506200025e620002bf366004620030b4565b620006e5565b348015620002d257600080fd5b50620001666201518081565b348015620002eb57600080fd5b5062000220620007ff565b3480156200030357600080fd5b506200025e62000819565b3480156200031b57600080fd5b506002546001600160a01b031662000220565b3480156200033b57600080fd5b50600a5460405161ffff909116815260200162000170565b3480156200036057600080fd5b5060045462000166565b620003816200037b36600462003282565b620008e3565b6040516001600160401b03909116815260200162000170565b62000381620003ab36600462003369565b620012c4565b348015620003be57600080fd5b5062000220620003d0366004620033a4565b61ffff166000908152600960205260409020546001600160a01b031690565b348015620003fc57600080fd5b506200025e6200040e366004620033c4565b620018f6565b3480156200042157600080fd5b506000546001600160a01b031662000220565b3480156200044157600080fd5b506200025e62000453366004620033de565b62001992565b3480156200046657600080fd5b506200025e62001a44565b3480156200047e57600080fd5b50620001ea62000490366004620030b4565b6001600160a01b031660009081526006602052604090205460ff1690565b60006001600160a01b0386163014620005245760405162461bcd60e51b815260206004820152602d60248201527f63616e206f6e6c792062726964676520746f6b656e7320766961207472616e7360448201526c19995c939195081b595d1a1bd9609a1b60648201526084015b60405180910390fd5b50630a85bd0160e11b95945050505050565b61ffff91909116600090815260076020908152604080832093835292905220546001600160a01b031690565b6002600b5403620005875760405162461bcd60e51b81526004016200051b9062003418565b6002600b556000546001600160a01b03163314620005e85760405162461bcd60e51b815260206004820152601b60248201527f4e6f742046726f6d205a4b427269646765456e747279706f696e74000000000060448201526064016200051b565b836001600160a01b0316620006168661ffff166000908152600960205260409020546001600160a01b031690565b6001600160a01b031614620006605760405162461bcd60e51b815260206004820152600f60248201526e34b73b30b634b21032b6b4ba3a32b960891b60448201526064016200051b565b6000620006a8600084848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505062001c8e9050565b90508060ff16600103620006ca57620006c48685858562001cee565b620006d8565b620006d88685858562001f96565b50506001600b5550505050565b33620006f96002546001600160a01b031690565b6001600160a01b031614620007225760405162461bcd60e51b81526004016200051b906200344f565b6001600160a01b0381166200077a5760405162461bcd60e51b815260206004820152601b60248201527f436865636b2070656e64696e67496d706c656d656e746174696f6e000000000060448201526064016200051b565b60006200078f6003546001600160a01b031690565b90506200079c82620023fb565b620007bb620007aa60055490565b620007b690426200349a565b600455565b816001600160a01b0316816001600160a01b03167fe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d81560405160405180910390a35050565b6000620008146001546001600160a01b031690565b905090565b60006200084d7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905062000872816001600160a01b031660009081526006602052604090205460ff1690565b15620008b75760405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064016200051b565b620008e0816001600160a01b03166000908152600660205260409020805460ff19166001179055565b50565b60006002600b54036200090a5760405162461bcd60e51b81526004016200051b9062003418565b6002600b558351855114620009515760405162461bcd60e51b815260206004820152600c60248201526b3632b733ba341032b93937b960a11b60448201526064016200051b565b600085516001600160401b038111156200096f576200096f620031a0565b60405190808252806020026020018201604052801562000999578160200160208202803683370190505b509050600086516001600160401b03811115620009ba57620009ba620031a0565b604051908082528060200260200182016040528015620009e4578160200160208202803683370190505b509050600087516001600160401b0381111562000a055762000a05620031a0565b60405190808252806020026020018201604052801562000a2f578160200160208202803683370190505b509050600088516001600160401b0381111562000a505762000a50620031a0565b60405190808252806020026020018201604052801562000a7a578160200160208202803683370190505b509050600089516001600160401b0381111562000a9b5762000a9b620031a0565b60405190808252806020026020018201604052801562000ad057816020015b606081526020019060019003908162000aba5790505b50905060008a516001600160401b0381111562000af15762000af1620031a0565b60405190808252806020026020018201604052801562000b1b578160200160208202803683370190505b50905060005b8b51811015620011905760008c828151811062000b425762000b42620034b5565b6020026020010151905060008c838151811062000b635762000b63620034b5565b6020026020010151905060008062000b93846001600160a01b031660009081526008602052604090205460ff1690565b1562000c6d57836001600160a01b0316639a8a05926040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000bd8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000bfe9190620034d8565b9150836001600160a01b0316633d6c043b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000c3f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c659190620034f8565b905062000daa565b600a5461ffff166040516301ffc9a760e01b81529092506001600160a01b038516915081906301ffc9a79062000caf906380ac58cd60e01b906004016200309f565b602060405180830381865afa15801562000ccd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000cf3919062003512565b62000d125760405162461bcd60e51b81526004016200051b9062003536565b6040516301ffc9a760e01b81526001600160a01b038516906301ffc9a79062000d4790635b5e139f60e01b906004016200309f565b602060405180830381865afa15801562000d65573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d8b919062003512565b62000daa5760405162461bcd60e51b81526004016200051b9062003577565b808b868151811062000dc05762000dc0620034b5565b602090810291909101810191909152604080516004815260248101825291820180516001600160e01b03166395d89b4160e01b17905251606091829182916000916001600160a01b038a169162000e1791620035f4565b600060405180830381855afa9150503d806000811462000e54576040519150601f19603f3d011682016040523d82523d6000602084013e62000e59565b606091505b5060408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b1790529051919350600092506001600160a01b038b169162000ea29190620035f4565b600060405180830381855afa9150503d806000811462000edf576040519150601f19603f3d011682016040523d82523d6000602084013e62000ee4565b606091505b509150508180602001905181019062000efe919062003686565b94508080602001905181019062000f16919062003686565b93506000896001600160a01b03168960405160240162000f3891815260200190565b60408051601f198184030181529181526020820180516001600160e01b031663c87b56dd60e01b1790525162000f6f9190620035f4565b600060405180830381855afa9150503d806000811462000fac576040519150601f19603f3d011682016040523d82523d6000602084013e62000fb1565b606091505b509150508080602001905181019062000fcb919062003686565b60208781015190870151604051632142170760e11b815292965090945092506001600160a01b038b1691506342842e0e906200101090339030908d90600401620036be565b600060405180830381600087803b1580156200102b57600080fd5b505af115801562001040573d6000803e3d6000fd5b5050505062001052600a5461ffff1690565b61ffff168761ffff1614620010be57604051630852cd8d60e31b8152600481018990526001600160a01b038a16906342966c6890602401600060405180830381600087803b158015620010a457600080fd5b505af1158015620010b9573d6000803e3d6000fd5b505050505b868f8b81518110620010d457620010d4620034b5565b602002602001019061ffff16908161ffff1681525050808e8b81518110620011005762001100620034b5565b602002602001018181525050818d8b81518110620011225762001122620034b5565b602002602001018181525050828c8b81518110620011445762001144620034b5565b6020026020010181905250878b8b81518110620011655762001165620034b5565b60200260200101818152505050505050505050505080806200118790620036e2565b91505062000b21565b50620011da6040518061010001604052808881526020018781526020018581526020018681526020018381526020018481526020018a81526020018b61ffff16815250346200241d565b965060005b8b51811015620012af57876001600160401b03167fe11d2ca26838f15acb41450029a785bb3d6f909b7f622ebf9c45524ded76f4118d8381518110620012295762001229620034b5565b60200260200101518d8481518110620012465762001246620034b5565b60200260200101518d336200125b8f6200259b565b604080516001600160a01b039687168152602081019590955261ffff93909316848401529084166060840152909216608082015290519081900360a00190a280620012a681620036e2565b915050620011df565b50506001600b55509398975050505050505050565b60006002600b5403620012eb5760405162461bcd60e51b81526004016200051b9062003418565b6002600b556001600160a01b038516600090815260086020526040812054819060ff1615620013e857866001600160a01b0316639a8a05926040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001353573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620013799190620034d8565b9150866001600160a01b0316633d6c043b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620013ba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620013e09190620034f8565b905062001525565b600a5461ffff166040516301ffc9a760e01b81529092506001600160a01b038816915081906301ffc9a7906200142a906380ac58cd60e01b906004016200309f565b602060405180830381865afa15801562001448573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200146e919062003512565b6200148d5760405162461bcd60e51b81526004016200051b9062003536565b6040516301ffc9a760e01b81526001600160a01b038816906301ffc9a790620014c290635b5e139f60e01b906004016200309f565b602060405180830381865afa158015620014e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001506919062003512565b620015255760405162461bcd60e51b81526004016200051b9062003577565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b1790529051606091829182916000916001600160a01b038d16916200156f91620035f4565b600060405180830381855afa9150503d8060008114620015ac576040519150601f19603f3d011682016040523d82523d6000602084013e620015b1565b606091505b5060408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b1790529051919350600092506001600160a01b038e1691620015fa9190620035f4565b600060405180830381855afa9150503d806000811462001637576040519150601f19603f3d011682016040523d82523d6000602084013e6200163c565b606091505b509150508180602001905181019062001656919062003686565b9450808060200190518101906200166e919062003686565b935060008c6001600160a01b03168c6040516024016200169091815260200190565b60408051601f198184030181529181526020820180516001600160e01b031663c87b56dd60e01b17905251620016c79190620035f4565b600060405180830381855afa9150503d806000811462001704576040519150601f19603f3d011682016040523d82523d6000602084013e62001709565b606091505b509150508080602001905181019062001723919062003686565b935050505060008060208501519150602084015190508b6001600160a01b03166342842e0e33308e6040518463ffffffff1660e01b81526004016200176b93929190620036be565b600060405180830381600087803b1580156200178657600080fd5b505af11580156200179b573d6000803e3d6000fd5b50505050620017ad600a5461ffff1690565b61ffff168761ffff16146200181957604051630852cd8d60e31b8152600481018c90526001600160a01b038d16906342966c6890602401600060405180830381600087803b158015620017ff57600080fd5b505af115801562001814573d6000803e3d6000fd5b505050505b620018666040518061010001604052808881526020018961ffff1681526020018481526020018381526020018d81526020018581526020018b81526020018c61ffff1681525034620025f1565b9750876001600160401b03167fe11d2ca26838f15acb41450029a785bb3d6f909b7f622ebf9c45524ded76f4118d8d8d33620018a28f6200259b565b604080516001600160a01b039687168152602081019590955261ffff93909316848401529084166060840152909216608082015290519081900360a00190a250506001600b55509398975050505050505050565b336200190a6002546001600160a01b031690565b6001600160a01b031614620019335760405162461bcd60e51b81526004016200051b906200344f565b62015180811015620019885760405162461bcd60e51b815260206004820152601b60248201527f496e636f7272656374206c6f636b54696d652073657474696e6773000000000060448201526064016200051b565b620008e081600555565b33620019a66002546001600160a01b031690565b6001600160a01b031614620019cf5760405162461bcd60e51b81526004016200051b906200344f565b61ffff8216600090815260096020526040902080546001600160a01b0319166001600160a01b0383161790556040805161ffff841681526001600160a01b03831660208201527faf4e2924b78f8cba0a0e626999cf99bb7a50dba42aab94e3030ed34e54e5c12c910160405180910390a15050565b3362001a586002546001600160a01b031690565b6001600160a01b03161462001a815760405162461bcd60e51b81526004016200051b906200344f565b600062001a966003546001600160a01b031690565b6001600160a01b03160362001aee5760405162461bcd60e51b815260206004820152601b60248201527f436865636b2070656e64696e67496d706c656d656e746174696f6e000000000060448201526064016200051b565b60045442101562001b345760405162461bcd60e51b815260206004820152600f60248201526e29ba34b636103637b1b5b2b21034b760891b60448201526064016200051b565b600062001b687f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b9050600062001b7f6003546001600160a01b031690565b905062001b8d6000620023fb565b62001b98816200262b565b60408051600481526024810182526020810180516001600160e01b031663204a7f0760e21b179052905160009182916001600160a01b0385169162001bdd91620035f4565b600060405180830381855af49150503d806000811462001c1a576040519150601f19603f3d011682016040523d82523d6000602084013e62001c1f565b606091505b509150915081819062001c475760405162461bcd60e51b81526004016200051b91906200372c565b50826001600160a01b0316846001600160a01b03167f2e4cc16c100f0b55e2df82ab0b1a7e294aa9cbd01b48fbaf622683fbc0507a4960405160405180910390a350505050565b600062001c9d8260016200349a565b8351101562001ce55760405162461bcd60e51b8152602060048201526013602482015272746f55696e74385f6f75744f66426f756e647360681b60448201526064016200051b565b50016001015190565b600062001d3183838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200266d92505050565b905062001d41600a5461ffff1690565b61ffff168160e0015161ffff161462001d945760405162461bcd60e51b815260206004820152601460248201527334b73b30b634b2103a30b933b2ba1031b430b4b760611b60448201526064016200051b565b600062001da4600a5461ffff1690565b61ffff16826020015161ffff160362001dcc57815162001dc4906200259b565b905062001e17565b600062001de28360200151846000015162000536565b90506001600160a01b03811662001e145762001e11836020015184600001518560600151866040015162002843565b90505b90505b600062001e288360c001516200259b565b905062001e38600a5461ffff1690565b61ffff16836020015161ffff161462001ebf57608083015160a08401516040516334ff261960e21b81526001600160a01b0385169263d3fc98649262001e85928692919060040162003741565b600060405180830381600087803b15801562001ea057600080fd5b505af115801562001eb5573d6000803e3d6000fd5b5050505062001f2a565b6080830151604051632142170760e11b81526001600160a01b038416916342842e0e9162001ef5913091869190600401620036be565b600060405180830381600087803b15801562001f1057600080fd5b505af115801562001f25573d6000803e3d6000fd5b505050505b856001600160401b03167f32aae95950c2e1f2c1a419165ba01c63c49604db10ee1b95d9960c0f5b9b9fa862001f6485600001516200259b565b84866080015187602001518c8760405162001f85969594939291906200376a565b60405180910390a250505050505050565b600062001fd983838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525062002aad92505050565b905062001fe9600a5461ffff1690565b61ffff168160e0015161ffff16146200203c5760405162461bcd60e51b815260206004820152601460248201527334b73b30b634b2103a30b933b2ba1031b430b4b760611b60448201526064016200051b565b60005b815151811015620023f35760006200205a600a5461ffff1690565b61ffff1683602001518381518110620020775762002077620034b5565b602002602001015161ffff1603620020bc57620020b483600001518381518110620020a657620020a6620034b5565b60200260200101516200259b565b9050620021af565b60006200210a84602001518481518110620020db57620020db620034b5565b602002602001015185600001518581518110620020fc57620020fc620034b5565b602002602001015162000536565b90506001600160a01b038116620021ac57620021a984602001518481518110620021385762002138620034b5565b602002602001015185600001518581518110620021595762002159620034b5565b6020026020010151866060015186815181106200217a576200217a620034b5565b6020026020010151876040015187815181106200219b576200219b620034b5565b602002602001015162002843565b90505b90505b6000620021c08460c001516200259b565b9050620021d0600a5461ffff1690565b61ffff1684602001518481518110620021ed57620021ed620034b5565b602002602001015161ffff1614620022ab57816001600160a01b031663d3fc98648286608001518681518110620022285762002228620034b5565b60200260200101518760a001518781518110620022495762002249620034b5565b60200260200101516040518463ffffffff1660e01b8152600401620022719392919062003741565b600060405180830381600087803b1580156200228c57600080fd5b505af1158015620022a1573d6000803e3d6000fd5b5050505062002332565b816001600160a01b03166342842e0e308387608001518781518110620022d557620022d5620034b5565b60200260200101516040518463ffffffff1660e01b8152600401620022fd93929190620036be565b600060405180830381600087803b1580156200231857600080fd5b505af11580156200232d573d6000803e3d6000fd5b505050505b866001600160401b03167f32aae95950c2e1f2c1a419165ba01c63c49604db10ee1b95d9960c0f5b9b9fa86200237a86600001518681518110620020a657620020a6620034b5565b8487608001518781518110620023945762002394620034b5565b602002602001015188602001518881518110620023b557620023b5620034b5565b60200260200101518d87604051620023d3969594939291906200376a565b60405180910390a250508080620023ea90620036e2565b9150506200203f565b505050505050565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000805b8360a0015151811015620024895760c88460a0015182815181106200244a576200244a620034b5565b6020026020010151511115620024745760405162461bcd60e51b81526004016200051b90620037a6565b806200248081620036e2565b91505062002421565b5082516020808501516040808701516060880151608089015160a08a015160c08b015160e08c01519551600099620024c69990989791016200387e565b60405160208183030381529060405290506000620025018560e0015161ffff166000908152600960205260409020546001600160a01b031690565b9050620025166000546001600160a01b031690565b6001600160a01b031663b1d995dd858760e0015184866040518563ffffffff1660e01b81526004016200254c9392919062003955565b60206040518083038185885af11580156200256b573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019062002592919062003985565b95945050505050565b60006001600160a01b0319821615620025ed5760405162461bcd60e51b8152602060048201526013602482015272696e76616c69642045564d206164647265737360681b60448201526064016200051b565b5090565b600080620025ff8462002b41565b90506000620025018560e0015161ffff166000908152600960205260409020546001600160a01b031690565b620026368162002bc3565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b604080516101008101825260008082526020820181905291810182905260608082018390526080820183905260a082015260c0810182905260e081018290529080620026ba848262001c8e565b9050620026c96001836200349a565b91508060ff16600114620027135760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b2102a3930b739b332b960811b60448201526064016200051b565b6200271f848362002c73565b83526200272e6020836200349a565b91506200273c848362002cd5565b61ffff166020840152620027526002836200349a565b915062002760848362002c73565b6040840152620027726020836200349a565b915062002780848362002c73565b6060840152620027926020836200349a565b9150620027a0848362002d36565b6080840152620027b26020836200349a565b9150620027c16001836200349a565b9150620027ee826022848751620027d99190620039a5565b620027e59190620039a5565b86919062002d8f565b60a08401528351915062002804600283620039a5565b915062002812848362002cd5565b61ffff1660e084015262002828602083620039a5565b915062002836848362002c73565b60c0840152509092915050565b600062002853600a5461ffff1690565b61ffff168561ffff1603620028bc5760405162461bcd60e51b815260206004820152602860248201527f63616e206f6e6c79207772617020746f6b656e732066726f6d20666f726569676044820152676e20636861696e7360c01b60648201526084016200051b565b6000620028ca868662000536565b6001600160a01b031614620029225760405162461bcd60e51b815260206004820152601c60248201527f7772617070656420617373657420616c7265616479206578697374730000000060448201526064016200051b565b6000627ce50b60e31b620029368562002ea8565b620029418562002ea8565b3089896040516024016200295a959493929190620039bf565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b03199095169490941790935251909250600091620029a491309185910162003a13565b6040516020818303038152906040529050600060405180602001620029c99062002fb3565b601f1982820381018352601f909101166040819052620029ef9190849060200162003a39565b60408051601f19818403018152908290526001600160f01b031960f08b901b166020830152602282018990529150600090604201604051602081830303815290604052805190602001209050808251602084016000f59450843b62002a5357600080fd5b61ffff891660009081526007602090815260408083208b8452825280832080546001600160a01b0319166001600160a01b038a16908117909155835260089091529020805460ff1916600117905550505050949350505050565b62002afd60405180610100016040528060608152602001606081526020016060815260200160608152602001606081526020016060815260200160008019168152602001600061ffff1681525090565b8180602001905181019062002b13919062003bc4565b61ffff1660e089015260c088015260a087015260808601526060850152604084015260208301528152919050565b606060c88260a0015151111562002b6c5760405162461bcd60e51b81526004016200051b90620037a6565b81516020808401516040808601516060870151608088015160a0890151805160c08b015160e08c0151965162002bad9a60019a909998939493910162003ce9565b6040516020818303038152906040529050919050565b6001600160a01b0381163b62002c325760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200051b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b600062002c828260206200349a565b8351101562002ccc5760405162461bcd60e51b8152602060048201526015602482015274746f427974657333325f6f75744f66426f756e647360581b60448201526064016200051b565b50016020015190565b600062002ce48260026200349a565b8351101562002d2d5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b60448201526064016200051b565b50016002015190565b600062002d458260206200349a565b8351101562002ccc5760405162461bcd60e51b8152602060048201526015602482015274746f55696e743235365f6f75744f66426f756e647360581b60448201526064016200051b565b60608162002d9f81601f6200349a565b101562002de05760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016200051b565b62002dec82846200349a565b8451101562002e325760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016200051b565b60608215801562002e53576040519150600082526020820160405262002e9f565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101562002e8e57805183526020928301920162002e74565b5050858452601f01601f1916604052505b50949350505050565b606060005b60208110801562002edf575082816020811062002ece5762002ece620034b5565b1a60f81b6001600160f81b03191615155b1562002efa578062002ef181620036e2565b91505062002ead565b6000816001600160401b0381111562002f175762002f17620031a0565b6040519080825280601f01601f19166020018201604052801562002f42576020820181803683370190505b50905060005b8281101562002fab5784816020811062002f665762002f66620034b5565b1a60f81b82828151811062002f7f5762002f7f620034b5565b60200101906001600160f81b031916908160001a9053508062002fa281620036e2565b91505062002f48565b509392505050565b61090b8062003d6a83390190565b80356001600160a01b038116811462002fd957600080fd5b919050565b60008083601f84011262002ff157600080fd5b5081356001600160401b038111156200300957600080fd5b6020830191508360208285010111156200302257600080fd5b9250929050565b6000806000806000608086880312156200304257600080fd5b6200304d8662002fc1565b94506200305d6020870162002fc1565b93506040860135925060608601356001600160401b038111156200308057600080fd5b6200308e8882890162002fde565b969995985093965092949392505050565b6001600160e01b031991909116815260200190565b600060208284031215620030c757600080fd5b620030d28262002fc1565b9392505050565b61ffff81168114620008e057600080fd5b803562002fd981620030d9565b600080604083850312156200310b57600080fd5b82356200311881620030d9565b946020939093013593505050565b6001600160401b0381168114620008e057600080fd5b6000806000806000608086880312156200315557600080fd5b85356200316281620030d9565b9450620031726020870162002fc1565b93506040860135620031848162003126565b925060608601356001600160401b038111156200308057600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620031e157620031e1620031a0565b604052919050565b60006001600160401b03821115620032055762003205620031a0565b5060051b60200190565b600082601f8301126200322157600080fd5b813560206200323a6200323483620031e9565b620031b6565b82815260059290921b840181019181810190868411156200325a57600080fd5b8286015b848110156200327757803583529183019183016200325e565b509695505050505050565b600080600080608085870312156200329957600080fd5b84356001600160401b0380821115620032b157600080fd5b818701915087601f830112620032c657600080fd5b81356020620032d96200323483620031e9565b82815260059290921b8401810191818101908b841115620032f957600080fd5b948201945b838610156200332257620033128662002fc1565b82529482019490820190620032fe565b985050880135925050808211156200333957600080fd5b5062003348878288016200320f565b9350506200335960408601620030ea565b9396929550929360600135925050565b600080600080608085870312156200338057600080fd5b6200338b8562002fc1565b93506020850135925060408501356200335981620030d9565b600060208284031215620033b757600080fd5b8135620030d281620030d9565b600060208284031215620033d757600080fd5b5035919050565b60008060408385031215620033f257600080fd5b8235620033ff81620030d9565b91506200340f6020840162002fc1565b90509250929050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008219821115620034b057620034b062003484565b500190565b634e487b7160e01b600052603260045260246000fd5b805162002fd981620030d9565b600060208284031215620034eb57600080fd5b8151620030d281620030d9565b6000602082840312156200350b57600080fd5b5051919050565b6000602082840312156200352557600080fd5b81518015158114620030d257600080fd5b60208082526021908201527f6d75737420737570706f7274207468652045524337323120696e7465726661636040820152606560f81b606082015260800190565b6020808252602a908201527f6d75737420737570706f727420746865204552433732312d4d657461646174616040820152691032bc3a32b739b4b7b760b11b606082015260800190565b60005b83811015620035de578181015183820152602001620035c4565b83811115620035ee576000848401525b50505050565b6000825162003608818460208701620035c1565b9190910192915050565b600082601f8301126200362457600080fd5b81516001600160401b03811115620036405762003640620031a0565b62003655601f8201601f1916602001620031b6565b8181528460208386010111156200366b57600080fd5b6200367e826020830160208701620035c1565b949350505050565b6000602082840312156200369957600080fd5b81516001600160401b03811115620036b057600080fd5b6200367e8482850162003612565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060018201620036f757620036f762003484565b5060010190565b6000815180845262003718816020860160208601620035c1565b601f01601f19169290920160200192915050565b602081526000620030d26020830184620036fe565b60018060a01b0384168152826020820152606060408201526000620025926060830184620036fe565b6001600160a01b0396871681529486166020860152604085019390935261ffff918216606085015216608083015290911660a082015260c00190565b60208082526022908201527f746f6b656e555249206d757374206e6f74206578636565642032303020627974604082015261657360f01b606082015260800190565b600081518084526020808501945080840160005b838110156200381a57815187529582019590820190600101620037fc565b509495945050505050565b600081518084526020808501808196508360051b8101915082860160005b85811015620038715782840389526200385e848351620036fe565b9885019893509084019060010162003843565b5091979650505050505050565b6000610100808352620038948184018c620037e8565b9050602083820381850152818b518084528284019150828d01935060005b81811015620038d457845161ffff1683529383019391830191600101620038b2565b50508481036040860152620038ea818c620037e8565b925050508281036060840152620039028189620037e8565b90508281036080840152620039188188620037e8565b905082810360a08401526200392e818762003825565b9150508360c08301526200394860e083018461ffff169052565b9998505050505050505050565b61ffff841681526001600160a01b03831660208201526060604082018190526000906200259290830184620036fe565b6000602082840312156200399857600080fd5b8151620030d28162003126565b600082821015620039ba57620039ba62003484565b500390565b60a081526000620039d460a0830188620036fe565b8281036020840152620039e88188620036fe565b6001600160a01b03969096166040840152505061ffff92909216606083015260809091015292915050565b6001600160a01b03831681526040602082018190526000906200367e90830184620036fe565b6000835162003a4d818460208801620035c1565b83519083019062003a63818360208801620035c1565b01949350505050565b600082601f83011262003a7e57600080fd5b8151602062003a916200323483620031e9565b82815260059290921b8401810191818101908684111562003ab157600080fd5b8286015b8481101562003277578051835291830191830162003ab5565b600082601f83011262003ae057600080fd5b8151602062003af36200323483620031e9565b82815260059290921b8401810191818101908684111562003b1357600080fd5b8286015b848110156200327757805162003b2d81620030d9565b835291830191830162003b17565b600082601f83011262003b4d57600080fd5b8151602062003b606200323483620031e9565b82815260059290921b8401810191818101908684111562003b8057600080fd5b8286015b84811015620032775780516001600160401b0381111562003ba55760008081fd5b62003bb58986838b010162003612565b84525091830191830162003b84565b600080600080600080600080610100898b03121562003be257600080fd5b88516001600160401b038082111562003bfa57600080fd5b62003c088c838d0162003a6c565b995060208b015191508082111562003c1f57600080fd5b62003c2d8c838d0162003ace565b985060408b015191508082111562003c4457600080fd5b62003c528c838d0162003a6c565b975060608b015191508082111562003c6957600080fd5b62003c778c838d0162003a6c565b965060808b015191508082111562003c8e57600080fd5b62003c9c8c838d0162003a6c565b955060a08b015191508082111562003cb357600080fd5b5062003cc28b828c0162003b3b565b93505060c0890151915062003cda60e08a01620034cb565b90509295985092959890939650565b600060ff60f81b808d60f81b1683528b600184015261ffff60f01b808c60f01b1660218501528a6023850152896043850152886063850152818860f81b1660838501528651915062003d43826084860160208a01620035c1565b920160848101949094525060f09190911b1660a482015260a6019897505050505050505056fe608060405234801561001057600080fd5b5060405161090b38038061090b83398101604081905261002f91610467565b818161003d82826000610046565b50505050610591565b61004f83610111565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a26000825111806100905750805b1561010c5761010a836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fa9190610527565b836102b460201b6100291760201c565b505b505050565b610124816102e060201b6100551760201c565b6101835760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101f7816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e89190610527565b6102e060201b6100551760201c565b61025c5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b606482015260840161017a565b806102937fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102ef60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102d983836040518060600160405280602781526020016108e4602791396102f2565b9392505050565b6001600160a01b03163b151590565b90565b60606001600160a01b0384163b61035a5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161017a565b600080856001600160a01b0316856040516103759190610542565b600060405180830381855af49150503d80600081146103b0576040519150601f19603f3d011682016040523d82523d6000602084013e6103b5565b606091505b5090925090506103c68282866103d0565b9695505050505050565b606083156103df5750816102d9565b8251156103ef5782518084602001fd5b8160405162461bcd60e51b815260040161017a919061055e565b80516001600160a01b038116811461042057600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561045657818101518382015260200161043e565b8381111561010a5750506000910152565b6000806040838503121561047a57600080fd5b61048383610409565b60208401519092506001600160401b03808211156104a057600080fd5b818501915085601f8301126104b457600080fd5b8151818111156104c6576104c6610425565b604051601f8201601f19908116603f011681019083821181831017156104ee576104ee610425565b8160405282815288602084870101111561050757600080fd5b61051883602083016020880161043b565b80955050505050509250929050565b60006020828403121561053957600080fd5b6102d982610409565b6000825161055481846020870161043b565b9190910192915050565b602081526000825180602084015261057d81604085016020870161043b565b601f01601f19169190910160400192915050565b610344806105a06000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102e860279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb919061023f565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b60606001600160a01b0384163b6101915760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084015b60405180910390fd5b600080856001600160a01b0316856040516101ac9190610298565b600060405180830381855af49150503d80600081146101e7576040519150601f19603f3d011682016040523d82523d6000602084013e6101ec565b606091505b50915091506101fc828286610206565b9695505050505050565b6060831561021557508161004e565b8251156102255782518084602001fd5b8160405162461bcd60e51b815260040161018891906102b4565b60006020828403121561025157600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b8381101561028357818101518382015260200161026b565b83811115610292576000848401525b50505050565b600082516102aa818460208701610268565b9190910192915050565b60208152600082518060208401526102d3816040850160208701610268565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220fbd9fa126cfa6a924f25fecc3873e70ac2ade0d0753dfdfe919e014c07c37bbe64736f6c634300080e0033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c5b26464ad008bd27bda8f49f2825bcdd42fabb88caa746f412575560d41427a64736f6c634300080e0033
Deployed Bytecode
0x6080604052600436106200014f5760003560e01c80638da5cb5b11620000b9578063ad66a5f11162000078578063ad66a5f114620003b1578063ae04d45d14620003ef578063b42446591462000414578063b6dc12361462000434578063d1dc83c21462000459578063d60b347f146200047157600080fd5b80638da5cb5b146200030e5780639a8a0592146200032e5780639f0a22a61462000353578063aba5ca04146200036a578063ac7b22dc146200039a57600080fd5b80632f3a3d5d11620001125780632f3a3d5d1462000260578063396f7b2314620002805780633a55275714620002a05780633ff0320714620002c55780635c60da1b14620002de5780638129fc1c14620002f657600080fd5b80630d6680871462000154578063150b7a0214620001795780631a2be4da14620001ad5780631ff1e28614620001fb5780632de9952a1462000239575b600080fd5b3480156200016157600080fd5b506005545b6040519081526020015b60405180910390f35b3480156200018657600080fd5b506200019e6200019836600462003029565b620004ae565b6040516200017091906200309f565b348015620001ba57600080fd5b50620001ea620001cc366004620030b4565b6001600160a01b031660009081526008602052604090205460ff1690565b604051901515815260200162000170565b3480156200020857600080fd5b50620002206200021a366004620030f7565b62000536565b6040516001600160a01b03909116815260200162000170565b3480156200024657600080fd5b506200025e620002583660046200313c565b62000562565b005b3480156200026d57600080fd5b506001546001600160a01b031662000220565b3480156200028d57600080fd5b506003546001600160a01b031662000220565b348015620002ad57600080fd5b506200025e620002bf366004620030b4565b620006e5565b348015620002d257600080fd5b50620001666201518081565b348015620002eb57600080fd5b5062000220620007ff565b3480156200030357600080fd5b506200025e62000819565b3480156200031b57600080fd5b506002546001600160a01b031662000220565b3480156200033b57600080fd5b50600a5460405161ffff909116815260200162000170565b3480156200036057600080fd5b5060045462000166565b620003816200037b36600462003282565b620008e3565b6040516001600160401b03909116815260200162000170565b62000381620003ab36600462003369565b620012c4565b348015620003be57600080fd5b5062000220620003d0366004620033a4565b61ffff166000908152600960205260409020546001600160a01b031690565b348015620003fc57600080fd5b506200025e6200040e366004620033c4565b620018f6565b3480156200042157600080fd5b506000546001600160a01b031662000220565b3480156200044157600080fd5b506200025e62000453366004620033de565b62001992565b3480156200046657600080fd5b506200025e62001a44565b3480156200047e57600080fd5b50620001ea62000490366004620030b4565b6001600160a01b031660009081526006602052604090205460ff1690565b60006001600160a01b0386163014620005245760405162461bcd60e51b815260206004820152602d60248201527f63616e206f6e6c792062726964676520746f6b656e7320766961207472616e7360448201526c19995c939195081b595d1a1bd9609a1b60648201526084015b60405180910390fd5b50630a85bd0160e11b95945050505050565b61ffff91909116600090815260076020908152604080832093835292905220546001600160a01b031690565b6002600b5403620005875760405162461bcd60e51b81526004016200051b9062003418565b6002600b556000546001600160a01b03163314620005e85760405162461bcd60e51b815260206004820152601b60248201527f4e6f742046726f6d205a4b427269646765456e747279706f696e74000000000060448201526064016200051b565b836001600160a01b0316620006168661ffff166000908152600960205260409020546001600160a01b031690565b6001600160a01b031614620006605760405162461bcd60e51b815260206004820152600f60248201526e34b73b30b634b21032b6b4ba3a32b960891b60448201526064016200051b565b6000620006a8600084848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505062001c8e9050565b90508060ff16600103620006ca57620006c48685858562001cee565b620006d8565b620006d88685858562001f96565b50506001600b5550505050565b33620006f96002546001600160a01b031690565b6001600160a01b031614620007225760405162461bcd60e51b81526004016200051b906200344f565b6001600160a01b0381166200077a5760405162461bcd60e51b815260206004820152601b60248201527f436865636b2070656e64696e67496d706c656d656e746174696f6e000000000060448201526064016200051b565b60006200078f6003546001600160a01b031690565b90506200079c82620023fb565b620007bb620007aa60055490565b620007b690426200349a565b600455565b816001600160a01b0316816001600160a01b03167fe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d81560405160405180910390a35050565b6000620008146001546001600160a01b031690565b905090565b60006200084d7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905062000872816001600160a01b031660009081526006602052604090205460ff1690565b15620008b75760405162461bcd60e51b8152602060048201526013602482015272185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064016200051b565b620008e0816001600160a01b03166000908152600660205260409020805460ff19166001179055565b50565b60006002600b54036200090a5760405162461bcd60e51b81526004016200051b9062003418565b6002600b558351855114620009515760405162461bcd60e51b815260206004820152600c60248201526b3632b733ba341032b93937b960a11b60448201526064016200051b565b600085516001600160401b038111156200096f576200096f620031a0565b60405190808252806020026020018201604052801562000999578160200160208202803683370190505b509050600086516001600160401b03811115620009ba57620009ba620031a0565b604051908082528060200260200182016040528015620009e4578160200160208202803683370190505b509050600087516001600160401b0381111562000a055762000a05620031a0565b60405190808252806020026020018201604052801562000a2f578160200160208202803683370190505b509050600088516001600160401b0381111562000a505762000a50620031a0565b60405190808252806020026020018201604052801562000a7a578160200160208202803683370190505b509050600089516001600160401b0381111562000a9b5762000a9b620031a0565b60405190808252806020026020018201604052801562000ad057816020015b606081526020019060019003908162000aba5790505b50905060008a516001600160401b0381111562000af15762000af1620031a0565b60405190808252806020026020018201604052801562000b1b578160200160208202803683370190505b50905060005b8b51811015620011905760008c828151811062000b425762000b42620034b5565b6020026020010151905060008c838151811062000b635762000b63620034b5565b6020026020010151905060008062000b93846001600160a01b031660009081526008602052604090205460ff1690565b1562000c6d57836001600160a01b0316639a8a05926040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000bd8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000bfe9190620034d8565b9150836001600160a01b0316633d6c043b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000c3f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c659190620034f8565b905062000daa565b600a5461ffff166040516301ffc9a760e01b81529092506001600160a01b038516915081906301ffc9a79062000caf906380ac58cd60e01b906004016200309f565b602060405180830381865afa15801562000ccd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000cf3919062003512565b62000d125760405162461bcd60e51b81526004016200051b9062003536565b6040516301ffc9a760e01b81526001600160a01b038516906301ffc9a79062000d4790635b5e139f60e01b906004016200309f565b602060405180830381865afa15801562000d65573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d8b919062003512565b62000daa5760405162461bcd60e51b81526004016200051b9062003577565b808b868151811062000dc05762000dc0620034b5565b602090810291909101810191909152604080516004815260248101825291820180516001600160e01b03166395d89b4160e01b17905251606091829182916000916001600160a01b038a169162000e1791620035f4565b600060405180830381855afa9150503d806000811462000e54576040519150601f19603f3d011682016040523d82523d6000602084013e62000e59565b606091505b5060408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b1790529051919350600092506001600160a01b038b169162000ea29190620035f4565b600060405180830381855afa9150503d806000811462000edf576040519150601f19603f3d011682016040523d82523d6000602084013e62000ee4565b606091505b509150508180602001905181019062000efe919062003686565b94508080602001905181019062000f16919062003686565b93506000896001600160a01b03168960405160240162000f3891815260200190565b60408051601f198184030181529181526020820180516001600160e01b031663c87b56dd60e01b1790525162000f6f9190620035f4565b600060405180830381855afa9150503d806000811462000fac576040519150601f19603f3d011682016040523d82523d6000602084013e62000fb1565b606091505b509150508080602001905181019062000fcb919062003686565b60208781015190870151604051632142170760e11b815292965090945092506001600160a01b038b1691506342842e0e906200101090339030908d90600401620036be565b600060405180830381600087803b1580156200102b57600080fd5b505af115801562001040573d6000803e3d6000fd5b5050505062001052600a5461ffff1690565b61ffff168761ffff1614620010be57604051630852cd8d60e31b8152600481018990526001600160a01b038a16906342966c6890602401600060405180830381600087803b158015620010a457600080fd5b505af1158015620010b9573d6000803e3d6000fd5b505050505b868f8b81518110620010d457620010d4620034b5565b602002602001019061ffff16908161ffff1681525050808e8b81518110620011005762001100620034b5565b602002602001018181525050818d8b81518110620011225762001122620034b5565b602002602001018181525050828c8b81518110620011445762001144620034b5565b6020026020010181905250878b8b81518110620011655762001165620034b5565b60200260200101818152505050505050505050505080806200118790620036e2565b91505062000b21565b50620011da6040518061010001604052808881526020018781526020018581526020018681526020018381526020018481526020018a81526020018b61ffff16815250346200241d565b965060005b8b51811015620012af57876001600160401b03167fe11d2ca26838f15acb41450029a785bb3d6f909b7f622ebf9c45524ded76f4118d8381518110620012295762001229620034b5565b60200260200101518d8481518110620012465762001246620034b5565b60200260200101518d336200125b8f6200259b565b604080516001600160a01b039687168152602081019590955261ffff93909316848401529084166060840152909216608082015290519081900360a00190a280620012a681620036e2565b915050620011df565b50506001600b55509398975050505050505050565b60006002600b5403620012eb5760405162461bcd60e51b81526004016200051b9062003418565b6002600b556001600160a01b038516600090815260086020526040812054819060ff1615620013e857866001600160a01b0316639a8a05926040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001353573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620013799190620034d8565b9150866001600160a01b0316633d6c043b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620013ba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620013e09190620034f8565b905062001525565b600a5461ffff166040516301ffc9a760e01b81529092506001600160a01b038816915081906301ffc9a7906200142a906380ac58cd60e01b906004016200309f565b602060405180830381865afa15801562001448573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200146e919062003512565b6200148d5760405162461bcd60e51b81526004016200051b9062003536565b6040516301ffc9a760e01b81526001600160a01b038816906301ffc9a790620014c290635b5e139f60e01b906004016200309f565b602060405180830381865afa158015620014e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001506919062003512565b620015255760405162461bcd60e51b81526004016200051b9062003577565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b1790529051606091829182916000916001600160a01b038d16916200156f91620035f4565b600060405180830381855afa9150503d8060008114620015ac576040519150601f19603f3d011682016040523d82523d6000602084013e620015b1565b606091505b5060408051600481526024810182526020810180516001600160e01b03166306fdde0360e01b1790529051919350600092506001600160a01b038e1691620015fa9190620035f4565b600060405180830381855afa9150503d806000811462001637576040519150601f19603f3d011682016040523d82523d6000602084013e6200163c565b606091505b509150508180602001905181019062001656919062003686565b9450808060200190518101906200166e919062003686565b935060008c6001600160a01b03168c6040516024016200169091815260200190565b60408051601f198184030181529181526020820180516001600160e01b031663c87b56dd60e01b17905251620016c79190620035f4565b600060405180830381855afa9150503d806000811462001704576040519150601f19603f3d011682016040523d82523d6000602084013e62001709565b606091505b509150508080602001905181019062001723919062003686565b935050505060008060208501519150602084015190508b6001600160a01b03166342842e0e33308e6040518463ffffffff1660e01b81526004016200176b93929190620036be565b600060405180830381600087803b1580156200178657600080fd5b505af11580156200179b573d6000803e3d6000fd5b50505050620017ad600a5461ffff1690565b61ffff168761ffff16146200181957604051630852cd8d60e31b8152600481018c90526001600160a01b038d16906342966c6890602401600060405180830381600087803b158015620017ff57600080fd5b505af115801562001814573d6000803e3d6000fd5b505050505b620018666040518061010001604052808881526020018961ffff1681526020018481526020018381526020018d81526020018581526020018b81526020018c61ffff1681525034620025f1565b9750876001600160401b03167fe11d2ca26838f15acb41450029a785bb3d6f909b7f622ebf9c45524ded76f4118d8d8d33620018a28f6200259b565b604080516001600160a01b039687168152602081019590955261ffff93909316848401529084166060840152909216608082015290519081900360a00190a250506001600b55509398975050505050505050565b336200190a6002546001600160a01b031690565b6001600160a01b031614620019335760405162461bcd60e51b81526004016200051b906200344f565b62015180811015620019885760405162461bcd60e51b815260206004820152601b60248201527f496e636f7272656374206c6f636b54696d652073657474696e6773000000000060448201526064016200051b565b620008e081600555565b33620019a66002546001600160a01b031690565b6001600160a01b031614620019cf5760405162461bcd60e51b81526004016200051b906200344f565b61ffff8216600090815260096020526040902080546001600160a01b0319166001600160a01b0383161790556040805161ffff841681526001600160a01b03831660208201527faf4e2924b78f8cba0a0e626999cf99bb7a50dba42aab94e3030ed34e54e5c12c910160405180910390a15050565b3362001a586002546001600160a01b031690565b6001600160a01b03161462001a815760405162461bcd60e51b81526004016200051b906200344f565b600062001a966003546001600160a01b031690565b6001600160a01b03160362001aee5760405162461bcd60e51b815260206004820152601b60248201527f436865636b2070656e64696e67496d706c656d656e746174696f6e000000000060448201526064016200051b565b60045442101562001b345760405162461bcd60e51b815260206004820152600f60248201526e29ba34b636103637b1b5b2b21034b760891b60448201526064016200051b565b600062001b687f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b9050600062001b7f6003546001600160a01b031690565b905062001b8d6000620023fb565b62001b98816200262b565b60408051600481526024810182526020810180516001600160e01b031663204a7f0760e21b179052905160009182916001600160a01b0385169162001bdd91620035f4565b600060405180830381855af49150503d806000811462001c1a576040519150601f19603f3d011682016040523d82523d6000602084013e62001c1f565b606091505b509150915081819062001c475760405162461bcd60e51b81526004016200051b91906200372c565b50826001600160a01b0316846001600160a01b03167f2e4cc16c100f0b55e2df82ab0b1a7e294aa9cbd01b48fbaf622683fbc0507a4960405160405180910390a350505050565b600062001c9d8260016200349a565b8351101562001ce55760405162461bcd60e51b8152602060048201526013602482015272746f55696e74385f6f75744f66426f756e647360681b60448201526064016200051b565b50016001015190565b600062001d3183838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200266d92505050565b905062001d41600a5461ffff1690565b61ffff168160e0015161ffff161462001d945760405162461bcd60e51b815260206004820152601460248201527334b73b30b634b2103a30b933b2ba1031b430b4b760611b60448201526064016200051b565b600062001da4600a5461ffff1690565b61ffff16826020015161ffff160362001dcc57815162001dc4906200259b565b905062001e17565b600062001de28360200151846000015162000536565b90506001600160a01b03811662001e145762001e11836020015184600001518560600151866040015162002843565b90505b90505b600062001e288360c001516200259b565b905062001e38600a5461ffff1690565b61ffff16836020015161ffff161462001ebf57608083015160a08401516040516334ff261960e21b81526001600160a01b0385169263d3fc98649262001e85928692919060040162003741565b600060405180830381600087803b15801562001ea057600080fd5b505af115801562001eb5573d6000803e3d6000fd5b5050505062001f2a565b6080830151604051632142170760e11b81526001600160a01b038416916342842e0e9162001ef5913091869190600401620036be565b600060405180830381600087803b15801562001f1057600080fd5b505af115801562001f25573d6000803e3d6000fd5b505050505b856001600160401b03167f32aae95950c2e1f2c1a419165ba01c63c49604db10ee1b95d9960c0f5b9b9fa862001f6485600001516200259b565b84866080015187602001518c8760405162001f85969594939291906200376a565b60405180910390a250505050505050565b600062001fd983838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525062002aad92505050565b905062001fe9600a5461ffff1690565b61ffff168160e0015161ffff16146200203c5760405162461bcd60e51b815260206004820152601460248201527334b73b30b634b2103a30b933b2ba1031b430b4b760611b60448201526064016200051b565b60005b815151811015620023f35760006200205a600a5461ffff1690565b61ffff1683602001518381518110620020775762002077620034b5565b602002602001015161ffff1603620020bc57620020b483600001518381518110620020a657620020a6620034b5565b60200260200101516200259b565b9050620021af565b60006200210a84602001518481518110620020db57620020db620034b5565b602002602001015185600001518581518110620020fc57620020fc620034b5565b602002602001015162000536565b90506001600160a01b038116620021ac57620021a984602001518481518110620021385762002138620034b5565b602002602001015185600001518581518110620021595762002159620034b5565b6020026020010151866060015186815181106200217a576200217a620034b5565b6020026020010151876040015187815181106200219b576200219b620034b5565b602002602001015162002843565b90505b90505b6000620021c08460c001516200259b565b9050620021d0600a5461ffff1690565b61ffff1684602001518481518110620021ed57620021ed620034b5565b602002602001015161ffff1614620022ab57816001600160a01b031663d3fc98648286608001518681518110620022285762002228620034b5565b60200260200101518760a001518781518110620022495762002249620034b5565b60200260200101516040518463ffffffff1660e01b8152600401620022719392919062003741565b600060405180830381600087803b1580156200228c57600080fd5b505af1158015620022a1573d6000803e3d6000fd5b5050505062002332565b816001600160a01b03166342842e0e308387608001518781518110620022d557620022d5620034b5565b60200260200101516040518463ffffffff1660e01b8152600401620022fd93929190620036be565b600060405180830381600087803b1580156200231857600080fd5b505af11580156200232d573d6000803e3d6000fd5b505050505b866001600160401b03167f32aae95950c2e1f2c1a419165ba01c63c49604db10ee1b95d9960c0f5b9b9fa86200237a86600001518681518110620020a657620020a6620034b5565b8487608001518781518110620023945762002394620034b5565b602002602001015188602001518881518110620023b557620023b5620034b5565b60200260200101518d87604051620023d3969594939291906200376a565b60405180910390a250508080620023ea90620036e2565b9150506200203f565b505050505050565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6000805b8360a0015151811015620024895760c88460a0015182815181106200244a576200244a620034b5565b6020026020010151511115620024745760405162461bcd60e51b81526004016200051b90620037a6565b806200248081620036e2565b91505062002421565b5082516020808501516040808701516060880151608089015160a08a015160c08b015160e08c01519551600099620024c69990989791016200387e565b60405160208183030381529060405290506000620025018560e0015161ffff166000908152600960205260409020546001600160a01b031690565b9050620025166000546001600160a01b031690565b6001600160a01b031663b1d995dd858760e0015184866040518563ffffffff1660e01b81526004016200254c9392919062003955565b60206040518083038185885af11580156200256b573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019062002592919062003985565b95945050505050565b60006001600160a01b0319821615620025ed5760405162461bcd60e51b8152602060048201526013602482015272696e76616c69642045564d206164647265737360681b60448201526064016200051b565b5090565b600080620025ff8462002b41565b90506000620025018560e0015161ffff166000908152600960205260409020546001600160a01b031690565b620026368162002bc3565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b604080516101008101825260008082526020820181905291810182905260608082018390526080820183905260a082015260c0810182905260e081018290529080620026ba848262001c8e565b9050620026c96001836200349a565b91508060ff16600114620027135760405162461bcd60e51b815260206004820152601060248201526f34b73b30b634b2102a3930b739b332b960811b60448201526064016200051b565b6200271f848362002c73565b83526200272e6020836200349a565b91506200273c848362002cd5565b61ffff166020840152620027526002836200349a565b915062002760848362002c73565b6040840152620027726020836200349a565b915062002780848362002c73565b6060840152620027926020836200349a565b9150620027a0848362002d36565b6080840152620027b26020836200349a565b9150620027c16001836200349a565b9150620027ee826022848751620027d99190620039a5565b620027e59190620039a5565b86919062002d8f565b60a08401528351915062002804600283620039a5565b915062002812848362002cd5565b61ffff1660e084015262002828602083620039a5565b915062002836848362002c73565b60c0840152509092915050565b600062002853600a5461ffff1690565b61ffff168561ffff1603620028bc5760405162461bcd60e51b815260206004820152602860248201527f63616e206f6e6c79207772617020746f6b656e732066726f6d20666f726569676044820152676e20636861696e7360c01b60648201526084016200051b565b6000620028ca868662000536565b6001600160a01b031614620029225760405162461bcd60e51b815260206004820152601c60248201527f7772617070656420617373657420616c7265616479206578697374730000000060448201526064016200051b565b6000627ce50b60e31b620029368562002ea8565b620029418562002ea8565b3089896040516024016200295a959493929190620039bf565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b03199095169490941790935251909250600091620029a491309185910162003a13565b6040516020818303038152906040529050600060405180602001620029c99062002fb3565b601f1982820381018352601f909101166040819052620029ef9190849060200162003a39565b60408051601f19818403018152908290526001600160f01b031960f08b901b166020830152602282018990529150600090604201604051602081830303815290604052805190602001209050808251602084016000f59450843b62002a5357600080fd5b61ffff891660009081526007602090815260408083208b8452825280832080546001600160a01b0319166001600160a01b038a16908117909155835260089091529020805460ff1916600117905550505050949350505050565b62002afd60405180610100016040528060608152602001606081526020016060815260200160608152602001606081526020016060815260200160008019168152602001600061ffff1681525090565b8180602001905181019062002b13919062003bc4565b61ffff1660e089015260c088015260a087015260808601526060850152604084015260208301528152919050565b606060c88260a0015151111562002b6c5760405162461bcd60e51b81526004016200051b90620037a6565b81516020808401516040808601516060870151608088015160a0890151805160c08b015160e08c0151965162002bad9a60019a909998939493910162003ce9565b6040516020818303038152906040529050919050565b6001600160a01b0381163b62002c325760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200051b565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b600062002c828260206200349a565b8351101562002ccc5760405162461bcd60e51b8152602060048201526015602482015274746f427974657333325f6f75744f66426f756e647360581b60448201526064016200051b565b50016020015190565b600062002ce48260026200349a565b8351101562002d2d5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b60448201526064016200051b565b50016002015190565b600062002d458260206200349a565b8351101562002ccc5760405162461bcd60e51b8152602060048201526015602482015274746f55696e743235365f6f75744f66426f756e647360581b60448201526064016200051b565b60608162002d9f81601f6200349a565b101562002de05760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016200051b565b62002dec82846200349a565b8451101562002e325760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016200051b565b60608215801562002e53576040519150600082526020820160405262002e9f565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101562002e8e57805183526020928301920162002e74565b5050858452601f01601f1916604052505b50949350505050565b606060005b60208110801562002edf575082816020811062002ece5762002ece620034b5565b1a60f81b6001600160f81b03191615155b1562002efa578062002ef181620036e2565b91505062002ead565b6000816001600160401b0381111562002f175762002f17620031a0565b6040519080825280601f01601f19166020018201604052801562002f42576020820181803683370190505b50905060005b8281101562002fab5784816020811062002f665762002f66620034b5565b1a60f81b82828151811062002f7f5762002f7f620034b5565b60200101906001600160f81b031916908160001a9053508062002fa281620036e2565b91505062002f48565b509392505050565b61090b8062003d6a83390190565b80356001600160a01b038116811462002fd957600080fd5b919050565b60008083601f84011262002ff157600080fd5b5081356001600160401b038111156200300957600080fd5b6020830191508360208285010111156200302257600080fd5b9250929050565b6000806000806000608086880312156200304257600080fd5b6200304d8662002fc1565b94506200305d6020870162002fc1565b93506040860135925060608601356001600160401b038111156200308057600080fd5b6200308e8882890162002fde565b969995985093965092949392505050565b6001600160e01b031991909116815260200190565b600060208284031215620030c757600080fd5b620030d28262002fc1565b9392505050565b61ffff81168114620008e057600080fd5b803562002fd981620030d9565b600080604083850312156200310b57600080fd5b82356200311881620030d9565b946020939093013593505050565b6001600160401b0381168114620008e057600080fd5b6000806000806000608086880312156200315557600080fd5b85356200316281620030d9565b9450620031726020870162002fc1565b93506040860135620031848162003126565b925060608601356001600160401b038111156200308057600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620031e157620031e1620031a0565b604052919050565b60006001600160401b03821115620032055762003205620031a0565b5060051b60200190565b600082601f8301126200322157600080fd5b813560206200323a6200323483620031e9565b620031b6565b82815260059290921b840181019181810190868411156200325a57600080fd5b8286015b848110156200327757803583529183019183016200325e565b509695505050505050565b600080600080608085870312156200329957600080fd5b84356001600160401b0380821115620032b157600080fd5b818701915087601f830112620032c657600080fd5b81356020620032d96200323483620031e9565b82815260059290921b8401810191818101908b841115620032f957600080fd5b948201945b838610156200332257620033128662002fc1565b82529482019490820190620032fe565b985050880135925050808211156200333957600080fd5b5062003348878288016200320f565b9350506200335960408601620030ea565b9396929550929360600135925050565b600080600080608085870312156200338057600080fd5b6200338b8562002fc1565b93506020850135925060408501356200335981620030d9565b600060208284031215620033b757600080fd5b8135620030d281620030d9565b600060208284031215620033d757600080fd5b5035919050565b60008060408385031215620033f257600080fd5b8235620033ff81620030d9565b91506200340f6020840162002fc1565b90509250929050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008219821115620034b057620034b062003484565b500190565b634e487b7160e01b600052603260045260246000fd5b805162002fd981620030d9565b600060208284031215620034eb57600080fd5b8151620030d281620030d9565b6000602082840312156200350b57600080fd5b5051919050565b6000602082840312156200352557600080fd5b81518015158114620030d257600080fd5b60208082526021908201527f6d75737420737570706f7274207468652045524337323120696e7465726661636040820152606560f81b606082015260800190565b6020808252602a908201527f6d75737420737570706f727420746865204552433732312d4d657461646174616040820152691032bc3a32b739b4b7b760b11b606082015260800190565b60005b83811015620035de578181015183820152602001620035c4565b83811115620035ee576000848401525b50505050565b6000825162003608818460208701620035c1565b9190910192915050565b600082601f8301126200362457600080fd5b81516001600160401b03811115620036405762003640620031a0565b62003655601f8201601f1916602001620031b6565b8181528460208386010111156200366b57600080fd5b6200367e826020830160208701620035c1565b949350505050565b6000602082840312156200369957600080fd5b81516001600160401b03811115620036b057600080fd5b6200367e8482850162003612565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060018201620036f757620036f762003484565b5060010190565b6000815180845262003718816020860160208601620035c1565b601f01601f19169290920160200192915050565b602081526000620030d26020830184620036fe565b60018060a01b0384168152826020820152606060408201526000620025926060830184620036fe565b6001600160a01b0396871681529486166020860152604085019390935261ffff918216606085015216608083015290911660a082015260c00190565b60208082526022908201527f746f6b656e555249206d757374206e6f74206578636565642032303020627974604082015261657360f01b606082015260800190565b600081518084526020808501945080840160005b838110156200381a57815187529582019590820190600101620037fc565b509495945050505050565b600081518084526020808501808196508360051b8101915082860160005b85811015620038715782840389526200385e848351620036fe565b9885019893509084019060010162003843565b5091979650505050505050565b6000610100808352620038948184018c620037e8565b9050602083820381850152818b518084528284019150828d01935060005b81811015620038d457845161ffff1683529383019391830191600101620038b2565b50508481036040860152620038ea818c620037e8565b925050508281036060840152620039028189620037e8565b90508281036080840152620039188188620037e8565b905082810360a08401526200392e818762003825565b9150508360c08301526200394860e083018461ffff169052565b9998505050505050505050565b61ffff841681526001600160a01b03831660208201526060604082018190526000906200259290830184620036fe565b6000602082840312156200399857600080fd5b8151620030d28162003126565b600082821015620039ba57620039ba62003484565b500390565b60a081526000620039d460a0830188620036fe565b8281036020840152620039e88188620036fe565b6001600160a01b03969096166040840152505061ffff92909216606083015260809091015292915050565b6001600160a01b03831681526040602082018190526000906200367e90830184620036fe565b6000835162003a4d818460208801620035c1565b83519083019062003a63818360208801620035c1565b01949350505050565b600082601f83011262003a7e57600080fd5b8151602062003a916200323483620031e9565b82815260059290921b8401810191818101908684111562003ab157600080fd5b8286015b8481101562003277578051835291830191830162003ab5565b600082601f83011262003ae057600080fd5b8151602062003af36200323483620031e9565b82815260059290921b8401810191818101908684111562003b1357600080fd5b8286015b848110156200327757805162003b2d81620030d9565b835291830191830162003b17565b600082601f83011262003b4d57600080fd5b8151602062003b606200323483620031e9565b82815260059290921b8401810191818101908684111562003b8057600080fd5b8286015b84811015620032775780516001600160401b0381111562003ba55760008081fd5b62003bb58986838b010162003612565b84525091830191830162003b84565b600080600080600080600080610100898b03121562003be257600080fd5b88516001600160401b038082111562003bfa57600080fd5b62003c088c838d0162003a6c565b995060208b015191508082111562003c1f57600080fd5b62003c2d8c838d0162003ace565b985060408b015191508082111562003c4457600080fd5b62003c528c838d0162003a6c565b975060608b015191508082111562003c6957600080fd5b62003c778c838d0162003a6c565b965060808b015191508082111562003c8e57600080fd5b62003c9c8c838d0162003a6c565b955060a08b015191508082111562003cb357600080fd5b5062003cc28b828c0162003b3b565b93505060c0890151915062003cda60e08a01620034cb565b90509295985092959890939650565b600060ff60f81b808d60f81b1683528b600184015261ffff60f01b808c60f01b1660218501528a6023850152896043850152886063850152818860f81b1660838501528651915062003d43826084860160208a01620035c1565b920160848101949094525060f09190911b1660a482015260a6019897505050505050505056fe608060405234801561001057600080fd5b5060405161090b38038061090b83398101604081905261002f91610467565b818161003d82826000610046565b50505050610591565b61004f83610111565b6040516001600160a01b038416907f1cf3b03a6cf19fa2baba4df148e9dcabedea7f8a5c07840e207e5c089be95d3e90600090a26000825111806100905750805b1561010c5761010a836001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fa9190610527565b836102b460201b6100291760201c565b505b505050565b610124816102e060201b6100551760201c565b6101835760405162461bcd60e51b815260206004820152602560248201527f455243313936373a206e657720626561636f6e206973206e6f74206120636f6e6044820152641d1c9858dd60da1b60648201526084015b60405180910390fd5b6101f7816001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e89190610527565b6102e060201b6100551760201c565b61025c5760405162461bcd60e51b815260206004820152603060248201527f455243313936373a20626561636f6e20696d706c656d656e746174696f6e206960448201526f1cc81b9bdd08184818dbdb9d1c9858dd60821b606482015260840161017a565b806102937fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5060001b6102ef60201b6100641760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b60606102d983836040518060600160405280602781526020016108e4602791396102f2565b9392505050565b6001600160a01b03163b151590565b90565b60606001600160a01b0384163b61035a5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b606482015260840161017a565b600080856001600160a01b0316856040516103759190610542565b600060405180830381855af49150503d80600081146103b0576040519150601f19603f3d011682016040523d82523d6000602084013e6103b5565b606091505b5090925090506103c68282866103d0565b9695505050505050565b606083156103df5750816102d9565b8251156103ef5782518084602001fd5b8160405162461bcd60e51b815260040161017a919061055e565b80516001600160a01b038116811461042057600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101561045657818101518382015260200161043e565b8381111561010a5750506000910152565b6000806040838503121561047a57600080fd5b61048383610409565b60208401519092506001600160401b03808211156104a057600080fd5b818501915085601f8301126104b457600080fd5b8151818111156104c6576104c6610425565b604051601f8201601f19908116603f011681019083821181831017156104ee576104ee610425565b8160405282815288602084870101111561050757600080fd5b61051883602083016020880161043b565b80955050505050509250929050565b60006020828403121561053957600080fd5b6102d982610409565b6000825161055481846020870161043b565b9190910192915050565b602081526000825180602084015261057d81604085016020870161043b565b601f01601f19169190910160400192915050565b610344806105a06000396000f3fe60806040523661001357610011610017565b005b6100115b610027610022610067565b610100565b565b606061004e83836040518060600160405280602781526020016102e860279139610124565b9392505050565b6001600160a01b03163b151590565b90565b600061009a7fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50546001600160a01b031690565b6001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fb919061023f565b905090565b3660008037600080366000845af43d6000803e80801561011f573d6000f35b3d6000fd5b60606001600160a01b0384163b6101915760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084015b60405180910390fd5b600080856001600160a01b0316856040516101ac9190610298565b600060405180830381855af49150503d80600081146101e7576040519150601f19603f3d011682016040523d82523d6000602084013e6101ec565b606091505b50915091506101fc828286610206565b9695505050505050565b6060831561021557508161004e565b8251156102255782518084602001fd5b8160405162461bcd60e51b815260040161018891906102b4565b60006020828403121561025157600080fd5b81516001600160a01b038116811461004e57600080fd5b60005b8381101561028357818101518382015260200161026b565b83811115610292576000848401525b50505050565b600082516102aa818460208701610268565b9190910192915050565b60208152600082518060208401526102d3816040850160208701610268565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220fbd9fa126cfa6a924f25fecc3873e70ac2ade0d0753dfdfe919e014c07c37bbe64736f6c634300080e0033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c5b26464ad008bd27bda8f49f2825bcdd42fabb88caa746f412575560d41427a64736f6c634300080e0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$3.07
Net Worth in GLMR
Token Allocations
ETH
76.88%
BNB
23.12%
POL
0.00%
Multichain Portfolio | 35 Chains
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.