Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- PromoVault2
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2024-09-26T15:33:50.988087Z
Contract source code
// SPDX-License-Identifier: No License (None)
pragma solidity 0.8.19;
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
function safeApprove(address token, address to, uint value) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
}
function safeTransfer(address token, address to, uint value) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
}
function safeTransferFrom(address token, address from, address to, uint value) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
}
function safeTransferETH(address to, uint value) internal {
(bool success,) = to.call{value:value}(new bytes(0));
require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
}
}
abstract contract Ownable {
address internal _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
_owner = msg.sender;
emit OwnershipTransferred(address(0), msg.sender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == msg.sender, "Ownable: caller is not the owner");
_;
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
}
contract PromoVault2 is Ownable {
using TransferHelper for address;
struct Airdrop {
uint128 balance; // available airdrop balance
uint64 vestingDate; // after this date when tokens can be claimed
uint64 deadline; // until this date tokens can be claimed
address token; // airdrop token
}
mapping(address signer => Airdrop) public airdrops;
mapping(bytes32 messageHash => bool processed) public isProcessed; // record processed messages
event VaultTransfer(address indexed token, address indexed signer, address indexed from, address to, uint256 value, uint256 nonce);
event CreateAirdrop(address signer, address token, uint256 amount);
event CloseAirdrop(address signer, address receiver, uint256 amount);
event Rescue(address _token, uint256 _amount);
bool public isPaused;
modifier isNotPaused() {
require(!isPaused, "is paused");
_;
}
function setPause(bool pause) external onlyOwner {
isPaused = pause;
}
function createAirdrop(
address token, // airdrop token
uint256 amount, // amount of tokens for airdrop
address signer // unique signer for this airdrop
) external isNotPaused {
require(signer != address(0) && airdrops[signer].token == address(0), "signer already was used");
airdrops[signer].token = token;
uint256 balance = IERC20(token).balanceOf(address(this));
token.safeTransferFrom(msg.sender, address(this), amount);
amount = IERC20(token).balanceOf(address(this)) - balance;
require(amount < 2**128, "too big amount");
airdrops[signer].balance = uint128(amount);
emit CreateAirdrop(signer, token, amount);
}
/*
// to sign message on the server-side use:
var vault = new web3.eth.Contract(VaultContractABI, VaultContractAddress);
var nonce = await vault.methods.nonces(from).call();
var messageHash = web3.utils.soliditySha3(signer, token, from, value, nonce, ChainId, VaultContractAddress);
var signature = web3.eth.accounts.sign(messageHash, PrivateKey);
*/
// claim promo tokens from vault to user's address. Can be called by any wallet
function claimTokens(
address signer, // signer of airdrop
address to, // transfer to address (user's address who received airdrop)
uint256 value, // amount of tokens to transfer
uint256 nonce, // nonce is used to if you need to airdrop tokens to the same user many times
bytes memory signature
) external isNotPaused {
claim(signer, to, to, value, nonce, signature);
}
// user transfers promo tokens from vault to some address. Must be called by user who received airdrop
function transferTokens(
address signer, // signer of airdrop
address to, // transfer to address (any address)
uint256 value, // amount of tokens to transfer
uint256 nonce, // nonce is used to if you need to airdrop tokens to the same user many times
bytes memory signature
) external isNotPaused {
claim(signer, msg.sender, to, value, nonce, signature);
}
function claim(
address signer, // signer of airdrop
address from, // transfer from address
address to, // transfer to address
uint256 value, // amount of tokens to transfer
uint256 nonce, // nonce is used to if you need to airdrop tokens to the same user many times
bytes memory signature
) internal {
Airdrop memory a = airdrops[signer];
require(a.token != address(0) && signer != address(0), "closed");
require(a.balance >= value, "Not enough tokens");
require(a.vestingDate <= block.timestamp, "under vesting");
require(a.deadline == 0 || a.deadline >= block.timestamp, "expired");
bytes32 messageHash = keccak256(
abi.encodePacked(
signer,
a.token,
from,
value,
nonce,
block.chainid,
address(this)
)
);
messageHash = prefixed(messageHash);
require(!isProcessed[messageHash], "already claimed");
require(signer == recoverSigner(messageHash, signature), "wrong signature");
isProcessed[messageHash] = true;
airdrops[signer].balance = a.balance - uint128(value);
a.token.safeTransfer(to, value);
emit VaultTransfer(a.token, signer, from, to, value, nonce);
}
function splitSignature(bytes memory sig)
internal
pure
returns (
uint8 v,
bytes32 r,
bytes32 s
)
{
require(sig.length == 65);
assembly {
// first 32 bytes, after the length prefix
r := mload(add(sig, 32))
// second 32 bytes
s := mload(add(sig, 64))
// final byte (first byte of the next 32 bytes)
v := byte(0, mload(add(sig, 96)))
}
}
function recoverSigner(bytes32 message, bytes memory sig)
internal
pure
returns (address)
{
uint8 v;
bytes32 r;
bytes32 s;
(v, r, s) = splitSignature(sig);
return ecrecover(message, v, r, s);
}
// Builds a prefixed hash to mimic the behavior of eth_sign.
function prefixed(bytes32 hash) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)
);
}
/*
// ERC223 callback
function tokenReceived(address, uint, bytes calldata) external pure returns(bytes4) {
return this.tokenReceived.selector;
}
*/
// owner can close airdrop before all tokens is claimed and transfer leftover tokens to receiver address
function closeAirdrop(address signer, address receiver) external onlyOwner {
Airdrop memory a = airdrops[signer];
require(a.token != address(0) && signer != address(0), "closed");
require(a.balance != 0, "Not enough tokens");
a.token.safeTransfer(receiver, uint256(a.balance));
airdrops[signer].balance = 0;
emit CloseAirdrop(signer, receiver, uint256(a.balance));
}
// allow owner to rescue tokens from contract
function rescueTokens(address token, uint256 amount) onlyOwner external {
if (token == address(0)) {
msg.sender.safeTransferETH(amount);
} else {
token.safeTransfer(msg.sender, amount);
}
emit Rescue(token, amount);
}
}
Contract ABI
[{"type":"event","name":"CloseAirdrop","inputs":[{"type":"address","name":"signer","internalType":"address","indexed":false},{"type":"address","name":"receiver","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"CreateAirdrop","inputs":[{"type":"address","name":"signer","internalType":"address","indexed":false},{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Rescue","inputs":[{"type":"address","name":"_token","internalType":"address","indexed":false},{"type":"uint256","name":"_amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"VaultTransfer","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"signer","internalType":"address","indexed":true},{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":false},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"uint256","name":"nonce","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint128","name":"balance","internalType":"uint128"},{"type":"uint64","name":"vestingDate","internalType":"uint64"},{"type":"uint64","name":"deadline","internalType":"uint64"},{"type":"address","name":"token","internalType":"address"}],"name":"airdrops","inputs":[{"type":"address","name":"signer","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimTokens","inputs":[{"type":"address","name":"signer","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"bytes","name":"signature","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"closeAirdrop","inputs":[{"type":"address","name":"signer","internalType":"address"},{"type":"address","name":"receiver","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"createAirdrop","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"signer","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isPaused","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"processed","internalType":"bool"}],"name":"isProcessed","inputs":[{"type":"bytes32","name":"messageHash","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescueTokens","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPause","inputs":[{"type":"bool","name":"pause","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferTokens","inputs":[{"type":"address","name":"signer","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"bytes","name":"signature","internalType":"bytes"}]}]
Contract Creation Code
0x608060405234801561001057600080fd5b50600080546001600160a01b0319163390811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a361140e8061005f6000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063b187bd2611610071578063b187bd26146101c2578063bedb86fb146101cf578063cbc20fe0146101e2578063dcc4a5fc146101f5578063f2fde38b14610208578063f6368f7b1461021b57600080fd5b806311c16896146100ae57806357376198146100e6578063690e6cc2146100fb5780638c86f0a71461010e5780638da5cb5b146101a7575b600080fd5b6100d16100bc3660046110b1565b60026020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6100f96100f43660046110e6565b61022e565b005b6100f9610109366004611110565b6102e7565b61016661011c366004611143565b600160208190526000918252604090912080549101546001600160801b0382169167ffffffffffffffff600160801b8204811692600160c01b90920416906001600160a01b031684565b604080516001600160801b0395909516855267ffffffffffffffff938416602086015291909216908301526001600160a01b031660608201526080016100dd565b6000546040516001600160a01b0390911681526020016100dd565b6003546100d19060ff1681565b6100f96101dd366004611176565b6104c3565b6100f96101f03660046111a9565b61050f565b6100f961020336600461128f565b610547565b6100f9610216366004611143565b6107ca565b6100f96102293660046111a9565b6108c3565b336102416000546001600160a01b031690565b6001600160a01b0316146102705760405162461bcd60e51b8152600401610267906112cb565b60405180910390fd5b6001600160a01b03821661028d5761028833826108f4565b6102a1565b6102a16001600160a01b03831633836109c2565b604080516001600160a01b0384168152602081018390527f542fa6bfee3b4746210fbdd1d83f9e49b65adde3639f8d8f165dd18347938af2910160405180910390a15050565b336102fa6000546001600160a01b031690565b6001600160a01b0316146103205760405162461bcd60e51b8152600401610267906112cb565b6001600160a01b03808316600090815260016020818152604092839020835160808101855281546001600160801b038116825267ffffffffffffffff600160801b8204811694830194909452600160c01b90049092169382019390935291015490911660608201819052158015906103a057506001600160a01b03831615155b6103d55760405162461bcd60e51b815260206004820152600660248201526518db1bdcd95960d21b6044820152606401610267565b80516001600160801b03166000036104235760405162461bcd60e51b81526020600482015260116024820152704e6f7420656e6f75676820746f6b656e7360781b6044820152606401610267565b8051606082015161044a916001600160a01b039091169084906001600160801b03166109c2565b6001600160a01b0383811660008181526001602090815260409182902080546001600160801b031916905584518251938452938616908301526001600160801b039092168183015290517f3ec192272fa9cf7c91850e76dbc4eb1665ed08972b0eca02adcfa50a875ed3d09181900360600190a1505050565b336104d66000546001600160a01b031690565b6001600160a01b0316146104fc5760405162461bcd60e51b8152600401610267906112cb565b6003805460ff1916911515919091179055565b60035460ff16156105325760405162461bcd60e51b815260040161026790611300565b610540853386868686610ad6565b5050505050565b60035460ff161561056a5760405162461bcd60e51b815260040161026790611300565b6001600160a01b0381161580159061059e57506001600160a01b038181166000908152600160208190526040909120015416155b6105ea5760405162461bcd60e51b815260206004820152601760248201527f7369676e657220616c72656164792077617320757365640000000000000000006044820152606401610267565b6001600160a01b03818116600090815260016020819052604080832090910180546001600160a01b0319169387169384179055516370a0823160e01b81523060048201529091906370a0823190602401602060405180830381865afa158015610657573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061067b9190611323565b90506106926001600160a01b038516333086610ed2565b6040516370a0823160e01b815230600482015281906001600160a01b038616906370a0823190602401602060405180830381865afa1580156106d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106fc9190611323565b6107069190611352565b9250600160801b831061074c5760405162461bcd60e51b815260206004820152600e60248201526d1d1bdbc8189a59c8185b5bdd5b9d60921b6044820152606401610267565b6001600160a01b0382811660008181526001602090815260409182902080546001600160801b0319166001600160801b0389161790558151928352928716928201929092529081018490527f8bb035a14e427c40fc1fb7f442d2a84d053d2cf217513ca816ca3a8af748c56c9060600160405180910390a150505050565b336107dd6000546001600160a01b031690565b6001600160a01b0316146108035760405162461bcd60e51b8152600401610267906112cb565b6001600160a01b0381166108685760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610267565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60035460ff16156108e65760405162461bcd60e51b815260040161026790611300565b610540858586868686610ad6565b604080516000808252602082019092526001600160a01b03841690839060405161091e9190611365565b60006040518083038185875af1925050503d806000811461095b576040519150601f19603f3d011682016040523d82523d6000602084013e610960565b606091505b50509050806109bd5760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610267565b505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691610a1e9190611365565b6000604051808303816000865af19150503d8060008114610a5b576040519150601f19603f3d011682016040523d82523d6000602084013e610a60565b606091505b5091509150818015610a8a575080511580610a8a575080806020019051810190610a8a9190611394565b6105405760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610267565b6001600160a01b03808716600090815260016020818152604092839020835160808101855281546001600160801b038116825267ffffffffffffffff600160801b8204811694830194909452600160c01b9004909216938201939093529101549091166060820181905215801590610b5657506001600160a01b03871615155b610b8b5760405162461bcd60e51b815260206004820152600660248201526518db1bdcd95960d21b6044820152606401610267565b80516001600160801b0316841115610bd95760405162461bcd60e51b81526020600482015260116024820152704e6f7420656e6f75676820746f6b656e7360781b6044820152606401610267565b42816020015167ffffffffffffffff161115610c275760405162461bcd60e51b815260206004820152600d60248201526c756e6465722076657374696e6760981b6044820152606401610267565b604081015167ffffffffffffffff161580610c50575042816040015167ffffffffffffffff1610155b610c865760405162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b6044820152606401610267565b6060808201516040516bffffffffffffffffffffffff198a841b8116602083015291831b8216603482015288831b82166048820152605c8101879052607c810186905246609c8201523090921b1660bc82015260009060d001604051602081830303815290604052805190602001209050610d4e816040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b60008181526002602052604090205490915060ff1615610da25760405162461bcd60e51b815260206004820152600f60248201526e185b1c9958591e4818db185a5b5959608a1b6044820152606401610267565b610dac8184611002565b6001600160a01b0316886001600160a01b031614610dfe5760405162461bcd60e51b815260206004820152600f60248201526e77726f6e67207369676e617475726560881b6044820152606401610267565b6000818152600260205260409020805460ff191660011790558151610e249086906113b1565b6001600160a01b03898116600090815260016020526040902080546001600160801b0319166001600160801b0393909316929092179091556060830151610e6d911687876109c2565b606080830151604080516001600160a01b038a81168252602082018a9052918101889052818b16938c831693909216917f9940b13f828ca3c69d28f507d3d8a43250000e65b24a5f15b99c37333f37831f910160405180910390a45050505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691610f369190611365565b6000604051808303816000865af19150503d8060008114610f73576040519150601f19603f3d011682016040523d82523d6000602084013e610f78565b606091505b5091509150818015610fa2575080511580610fa2575080806020019051810190610fa29190611394565b610ffa5760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610267565b505050505050565b60008060008061101185611082565b6040805160008152602081018083528b905260ff8516918101919091526060810183905260808101829052929550909350915060019060a0016020604051602081039080840390855afa15801561106c573d6000803e3d6000fd5b5050506020604051035193505050505b92915050565b6000806000835160411461109557600080fd5b5050506020810151604082015160609092015160001a92909190565b6000602082840312156110c357600080fd5b5035919050565b80356001600160a01b03811681146110e157600080fd5b919050565b600080604083850312156110f957600080fd5b611102836110ca565b946020939093013593505050565b6000806040838503121561112357600080fd5b61112c836110ca565b915061113a602084016110ca565b90509250929050565b60006020828403121561115557600080fd5b61115e826110ca565b9392505050565b801515811461117357600080fd5b50565b60006020828403121561118857600080fd5b813561115e81611165565b634e487b7160e01b600052604160045260246000fd5b600080600080600060a086880312156111c157600080fd5b6111ca866110ca565b94506111d8602087016110ca565b93506040860135925060608601359150608086013567ffffffffffffffff8082111561120357600080fd5b818801915088601f83011261121757600080fd5b81358181111561122957611229611193565b604051601f8201601f19908116603f0116810190838211818310171561125157611251611193565b816040528281528b602084870101111561126a57600080fd5b8260208601602083013760006020848301015280955050505050509295509295909350565b6000806000606084860312156112a457600080fd5b6112ad846110ca565b9250602084013591506112c2604085016110ca565b90509250925092565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252600990820152681a5cc81c185d5cd95960ba1b604082015260600190565b60006020828403121561133557600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561107c5761107c61133c565b6000825160005b81811015611386576020818601810151858301520161136c565b506000920191825250919050565b6000602082840312156113a657600080fd5b815161115e81611165565b6001600160801b038281168282160390808211156113d1576113d161133c565b509291505056fea264697066735822122001263d14cff3fd2c06455d2b06932ca56d052a3400aebc792c7b4969c5bc56f164736f6c63430008130033
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106100a95760003560e01c8063b187bd2611610071578063b187bd26146101c2578063bedb86fb146101cf578063cbc20fe0146101e2578063dcc4a5fc146101f5578063f2fde38b14610208578063f6368f7b1461021b57600080fd5b806311c16896146100ae57806357376198146100e6578063690e6cc2146100fb5780638c86f0a71461010e5780638da5cb5b146101a7575b600080fd5b6100d16100bc3660046110b1565b60026020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6100f96100f43660046110e6565b61022e565b005b6100f9610109366004611110565b6102e7565b61016661011c366004611143565b600160208190526000918252604090912080549101546001600160801b0382169167ffffffffffffffff600160801b8204811692600160c01b90920416906001600160a01b031684565b604080516001600160801b0395909516855267ffffffffffffffff938416602086015291909216908301526001600160a01b031660608201526080016100dd565b6000546040516001600160a01b0390911681526020016100dd565b6003546100d19060ff1681565b6100f96101dd366004611176565b6104c3565b6100f96101f03660046111a9565b61050f565b6100f961020336600461128f565b610547565b6100f9610216366004611143565b6107ca565b6100f96102293660046111a9565b6108c3565b336102416000546001600160a01b031690565b6001600160a01b0316146102705760405162461bcd60e51b8152600401610267906112cb565b60405180910390fd5b6001600160a01b03821661028d5761028833826108f4565b6102a1565b6102a16001600160a01b03831633836109c2565b604080516001600160a01b0384168152602081018390527f542fa6bfee3b4746210fbdd1d83f9e49b65adde3639f8d8f165dd18347938af2910160405180910390a15050565b336102fa6000546001600160a01b031690565b6001600160a01b0316146103205760405162461bcd60e51b8152600401610267906112cb565b6001600160a01b03808316600090815260016020818152604092839020835160808101855281546001600160801b038116825267ffffffffffffffff600160801b8204811694830194909452600160c01b90049092169382019390935291015490911660608201819052158015906103a057506001600160a01b03831615155b6103d55760405162461bcd60e51b815260206004820152600660248201526518db1bdcd95960d21b6044820152606401610267565b80516001600160801b03166000036104235760405162461bcd60e51b81526020600482015260116024820152704e6f7420656e6f75676820746f6b656e7360781b6044820152606401610267565b8051606082015161044a916001600160a01b039091169084906001600160801b03166109c2565b6001600160a01b0383811660008181526001602090815260409182902080546001600160801b031916905584518251938452938616908301526001600160801b039092168183015290517f3ec192272fa9cf7c91850e76dbc4eb1665ed08972b0eca02adcfa50a875ed3d09181900360600190a1505050565b336104d66000546001600160a01b031690565b6001600160a01b0316146104fc5760405162461bcd60e51b8152600401610267906112cb565b6003805460ff1916911515919091179055565b60035460ff16156105325760405162461bcd60e51b815260040161026790611300565b610540853386868686610ad6565b5050505050565b60035460ff161561056a5760405162461bcd60e51b815260040161026790611300565b6001600160a01b0381161580159061059e57506001600160a01b038181166000908152600160208190526040909120015416155b6105ea5760405162461bcd60e51b815260206004820152601760248201527f7369676e657220616c72656164792077617320757365640000000000000000006044820152606401610267565b6001600160a01b03818116600090815260016020819052604080832090910180546001600160a01b0319169387169384179055516370a0823160e01b81523060048201529091906370a0823190602401602060405180830381865afa158015610657573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061067b9190611323565b90506106926001600160a01b038516333086610ed2565b6040516370a0823160e01b815230600482015281906001600160a01b038616906370a0823190602401602060405180830381865afa1580156106d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106fc9190611323565b6107069190611352565b9250600160801b831061074c5760405162461bcd60e51b815260206004820152600e60248201526d1d1bdbc8189a59c8185b5bdd5b9d60921b6044820152606401610267565b6001600160a01b0382811660008181526001602090815260409182902080546001600160801b0319166001600160801b0389161790558151928352928716928201929092529081018490527f8bb035a14e427c40fc1fb7f442d2a84d053d2cf217513ca816ca3a8af748c56c9060600160405180910390a150505050565b336107dd6000546001600160a01b031690565b6001600160a01b0316146108035760405162461bcd60e51b8152600401610267906112cb565b6001600160a01b0381166108685760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610267565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60035460ff16156108e65760405162461bcd60e51b815260040161026790611300565b610540858586868686610ad6565b604080516000808252602082019092526001600160a01b03841690839060405161091e9190611365565b60006040518083038185875af1925050503d806000811461095b576040519150601f19603f3d011682016040523d82523d6000602084013e610960565b606091505b50509050806109bd5760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960448201526213115160ea1b6064820152608401610267565b505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691610a1e9190611365565b6000604051808303816000865af19150503d8060008114610a5b576040519150601f19603f3d011682016040523d82523d6000602084013e610a60565b606091505b5091509150818015610a8a575080511580610a8a575080806020019051810190610a8a9190611394565b6105405760405162461bcd60e51b815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610267565b6001600160a01b03808716600090815260016020818152604092839020835160808101855281546001600160801b038116825267ffffffffffffffff600160801b8204811694830194909452600160c01b9004909216938201939093529101549091166060820181905215801590610b5657506001600160a01b03871615155b610b8b5760405162461bcd60e51b815260206004820152600660248201526518db1bdcd95960d21b6044820152606401610267565b80516001600160801b0316841115610bd95760405162461bcd60e51b81526020600482015260116024820152704e6f7420656e6f75676820746f6b656e7360781b6044820152606401610267565b42816020015167ffffffffffffffff161115610c275760405162461bcd60e51b815260206004820152600d60248201526c756e6465722076657374696e6760981b6044820152606401610267565b604081015167ffffffffffffffff161580610c50575042816040015167ffffffffffffffff1610155b610c865760405162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b6044820152606401610267565b6060808201516040516bffffffffffffffffffffffff198a841b8116602083015291831b8216603482015288831b82166048820152605c8101879052607c810186905246609c8201523090921b1660bc82015260009060d001604051602081830303815290604052805190602001209050610d4e816040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b60008181526002602052604090205490915060ff1615610da25760405162461bcd60e51b815260206004820152600f60248201526e185b1c9958591e4818db185a5b5959608a1b6044820152606401610267565b610dac8184611002565b6001600160a01b0316886001600160a01b031614610dfe5760405162461bcd60e51b815260206004820152600f60248201526e77726f6e67207369676e617475726560881b6044820152606401610267565b6000818152600260205260409020805460ff191660011790558151610e249086906113b1565b6001600160a01b03898116600090815260016020526040902080546001600160801b0319166001600160801b0393909316929092179091556060830151610e6d911687876109c2565b606080830151604080516001600160a01b038a81168252602082018a9052918101889052818b16938c831693909216917f9940b13f828ca3c69d28f507d3d8a43250000e65b24a5f15b99c37333f37831f910160405180910390a45050505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691610f369190611365565b6000604051808303816000865af19150503d8060008114610f73576040519150601f19603f3d011682016040523d82523d6000602084013e610f78565b606091505b5091509150818015610fa2575080511580610fa2575080806020019051810190610fa29190611394565b610ffa5760405162461bcd60e51b8152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f46416044820152631253115160e21b6064820152608401610267565b505050505050565b60008060008061101185611082565b6040805160008152602081018083528b905260ff8516918101919091526060810183905260808101829052929550909350915060019060a0016020604051602081039080840390855afa15801561106c573d6000803e3d6000fd5b5050506020604051035193505050505b92915050565b6000806000835160411461109557600080fd5b5050506020810151604082015160609092015160001a92909190565b6000602082840312156110c357600080fd5b5035919050565b80356001600160a01b03811681146110e157600080fd5b919050565b600080604083850312156110f957600080fd5b611102836110ca565b946020939093013593505050565b6000806040838503121561112357600080fd5b61112c836110ca565b915061113a602084016110ca565b90509250929050565b60006020828403121561115557600080fd5b61115e826110ca565b9392505050565b801515811461117357600080fd5b50565b60006020828403121561118857600080fd5b813561115e81611165565b634e487b7160e01b600052604160045260246000fd5b600080600080600060a086880312156111c157600080fd5b6111ca866110ca565b94506111d8602087016110ca565b93506040860135925060608601359150608086013567ffffffffffffffff8082111561120357600080fd5b818801915088601f83011261121757600080fd5b81358181111561122957611229611193565b604051601f8201601f19908116603f0116810190838211818310171561125157611251611193565b816040528281528b602084870101111561126a57600080fd5b8260208601602083013760006020848301015280955050505050509295509295909350565b6000806000606084860312156112a457600080fd5b6112ad846110ca565b9250602084013591506112c2604085016110ca565b90509250925092565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252600990820152681a5cc81c185d5cd95960ba1b604082015260600190565b60006020828403121561133557600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561107c5761107c61133c565b6000825160005b81811015611386576020818601810151858301520161136c565b506000920191825250919050565b6000602082840312156113a657600080fd5b815161115e81611165565b6001600160801b038281168282160390808211156113d1576113d161133c565b509291505056fea264697066735822122001263d14cff3fd2c06455d2b06932ca56d052a3400aebc792c7b4969c5bc56f164736f6c63430008130033