Source Code
Overview
MON Balance
MON Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
ArchetypeLogicErc1155
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 1 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
// ArchetypeLogic v0.8.1 - ERC1155
//
// d8888 888 888
// d88888 888 888
// d88P888 888 888
// d88P 888 888d888 .d8888b 88888b. .d88b. 888888 888 888 88888b. .d88b.
// d88P 888 888P" d88P" 888 "88b d8P Y8b 888 888 888 888 "88b d8P Y8b
// d88P 888 888 888 888 888 88888888 888 888 888 888 888 88888888
// d8888888888 888 Y88b. 888 888 Y8b. Y88b. Y88b 888 888 d88P Y8b.
// d88P 888 888 "Y8888P 888 888 "Y8888 "Y888 "Y88888 88888P" "Y8888
// 888 888
// Y8b d88P 888
// "Y88P" 888
pragma solidity ^0.8.20;
import "../ArchetypePayouts.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "solady/src/utils/MerkleProofLib.sol";
import "solady/src/utils/ECDSA.sol";
using SafeERC20 for IERC20;
error InvalidConfig();
error MintNotYetStarted();
error MintEnded();
error WalletUnauthorizedToMint();
error InsufficientEthSent();
error ExcessiveEthSent();
error Erc20BalanceTooLow();
error MaxSupplyExceeded();
error ListMaxSupplyExceeded();
error NumberOfMintsExceeded();
error MintingPaused();
error InvalidReferral();
error InvalidSignature();
error MaxBatchSizeExceeded();
error NotTokenOwner();
error NotPlatform();
error NotOwner();
error NotShareholder();
error NotApprovedToTransfer();
error InvalidAmountOfTokens();
error WrongPassword();
error LockedForever();
error URIQueryForNonexistentToken();
error InvalidTokenId();
error MintToZeroAddress();
error NotSupported();
//
// STRUCTS
//
struct Auth {
bytes32 key;
bytes32[] proof;
}
struct Config {
string baseUri;
address affiliateSigner;
uint32[] maxSupply; // max supply for each mintable tokenId
uint16 maxBatchSize;
uint16 affiliateFee; //BPS
uint16 affiliateDiscount; //BPS
uint16 defaultRoyalty; //BPS
}
struct PayoutConfig {
uint16 ownerBps;
uint16 platformBps;
uint16 partnerBps;
uint16 superAffiliateBps;
address partner;
address superAffiliate;
address ownerAltPayout;
}
struct Options {
bool uriLocked;
bool maxSupplyLocked;
bool affiliateFeeLocked;
bool ownerAltPayoutLocked;
}
struct AdvancedInvite {
uint128 price;
uint128 reservePrice;
uint128 delta;
uint32 start;
uint32 end;
uint32 limit;
uint32 maxSupply;
uint32 interval;
uint32 unitSize; // mint 1 get x
uint32[] tokenIds; // token ids mintable from this list
address tokenAddress;
}
struct Invite {
uint128 price;
uint32 start;
uint32 end;
uint32 limit;
uint32 maxSupply;
uint32 unitSize; // mint 1 get x
uint32[] tokenIds; // token ids mintable from this list
address tokenAddress;
}
struct ValidationArgs {
address owner;
address affiliate;
uint256[] quantities;
uint256[] tokenIds;
uint256 totalQuantity;
uint256 listSupply;
}
// UPDATE CONSTANTS BEFORE DEPLOY
address constant PLATFORM = 0x86B82972282Dd22348374bC63fd21620F7ED847B;
address constant BATCH = 0xEa49e7bE310716dA66725c84a5127d2F6A202eAf;
address constant PAYOUTS = 0xaAfdfA4a935d8511bF285af11A0544ce7e4a1199;
uint16 constant MAXBPS = 5000; // max fee or discount is 50%
uint32 constant UINT32_MAX = 2**32 - 1;
library ArchetypeLogicErc1155 {
//
// EVENTS
//
event Invited(bytes32 indexed key, bytes32 indexed cid);
event Referral(address indexed affiliate, address token, uint128 wad, uint256 numMints);
event Withdrawal(address indexed src, address token, uint128 wad);
// calculate price based on affiliate usage and mint discounts
function computePrice(
AdvancedInvite storage invite,
uint16 affiliateDiscount,
uint256 numTokens,
uint256 listSupply,
bool affiliateUsed
) public view returns (uint256) {
uint256 price = invite.price;
uint256 cost;
if (invite.interval > 0 && invite.delta > 0) {
// Apply dutch pricing
uint256 diff = (((block.timestamp - invite.start) / invite.interval) * invite.delta);
if (price > invite.reservePrice) {
if (diff > price - invite.reservePrice) {
price = invite.reservePrice;
} else {
price = price - diff;
}
} else if (price < invite.reservePrice) {
if (diff > invite.reservePrice - price) {
price = invite.reservePrice;
} else {
price = price + diff;
}
}
cost = price * numTokens;
} else if (invite.interval == 0 && invite.delta > 0) {
// Apply linear curve
uint256 lastPrice = price + invite.delta * listSupply;
cost = lastPrice * numTokens + (invite.delta * numTokens * (numTokens - 1)) / 2;
} else {
cost = price * numTokens;
}
if (affiliateUsed) {
cost = cost - ((cost * affiliateDiscount) / 10000);
}
return cost;
}
function validateMint(
AdvancedInvite storage i,
Config storage config,
Auth calldata auth,
mapping(address => mapping(bytes32 => uint256)) storage minted,
uint256[] storage tokenSupply,
bytes calldata signature,
ValidationArgs memory args,
uint256 cost
) public view {
address msgSender = _msgSender();
if (args.affiliate != address(0)) {
if (
args.affiliate == PLATFORM || args.affiliate == args.owner || args.affiliate == msgSender
) {
revert InvalidReferral();
}
validateAffiliate(args.affiliate, signature, config.affiliateSigner);
}
if (i.limit == 0) {
revert MintingPaused();
}
if (!verify(auth, i.tokenAddress, msgSender)) {
revert WalletUnauthorizedToMint();
}
if (block.timestamp < i.start) {
revert MintNotYetStarted();
}
if (i.end > i.start && block.timestamp > i.end) {
revert MintEnded();
}
uint256 totalQuantity = 0;
for (uint256 j = 0; j < args.quantities.length; j++) {
totalQuantity += args.quantities[j];
}
{
uint256 totalAfterMint;
if (i.limit < i.maxSupply) {
totalAfterMint = minted[msgSender][auth.key] + totalQuantity;
if (totalAfterMint > i.limit) {
revert NumberOfMintsExceeded();
}
}
if (i.maxSupply < UINT32_MAX) {
totalAfterMint = args.listSupply + totalQuantity;
if (totalAfterMint > i.maxSupply) {
revert ListMaxSupplyExceeded();
}
}
}
uint256[] memory checked = new uint256[](tokenSupply.length);
for (uint256 j = 0; j < args.tokenIds.length; j++) {
uint256 tokenId = args.tokenIds[j];
if (i.tokenIds.length != 0) {
bool isValid = false;
for (uint256 k = 0; k < i.tokenIds.length; k++) {
if (tokenId == i.tokenIds[k]) {
isValid = true;
break;
}
}
if (!isValid) {
revert InvalidTokenId();
}
}
if (
(tokenSupply[tokenId - 1] + checked[tokenId - 1] + args.quantities[j]) >
config.maxSupply[tokenId - 1]
) {
revert MaxSupplyExceeded();
}
checked[tokenId - 1] += args.quantities[j];
}
if (totalQuantity > config.maxBatchSize) {
revert MaxBatchSizeExceeded();
}
if (i.tokenAddress != address(0)) {
IERC20 erc20Token = IERC20(i.tokenAddress);
if (erc20Token.allowance(msgSender, address(this)) < cost) {
revert NotApprovedToTransfer();
}
if (erc20Token.balanceOf(msgSender) < cost) {
revert Erc20BalanceTooLow();
}
if (msg.value != 0) {
revert ExcessiveEthSent();
}
} else {
if (msg.value < cost) {
revert InsufficientEthSent();
}
}
}
function updateBalances(
AdvancedInvite storage i,
Config storage config,
mapping(address => uint128) storage _ownerBalance,
mapping(address => mapping(address => uint128)) storage _affiliateBalance,
address affiliate,
uint256 quantity,
uint128 value
) public {
address tokenAddress = i.tokenAddress;
uint128 affiliateWad;
if (affiliate != address(0)) {
affiliateWad = (value * config.affiliateFee) / 10000;
_affiliateBalance[affiliate][tokenAddress] += affiliateWad;
emit Referral(affiliate, tokenAddress, affiliateWad, quantity);
}
uint128 balance = _ownerBalance[tokenAddress];
uint128 ownerWad = value - affiliateWad;
_ownerBalance[tokenAddress] = balance + ownerWad;
if (tokenAddress != address(0)) {
IERC20 erc20Token = IERC20(tokenAddress);
erc20Token.safeTransferFrom(_msgSender(), address(this), value);
}
}
function withdrawTokensAffiliate(
mapping(address => mapping(address => uint128)) storage _affiliateBalance,
address[] calldata tokens
) public {
address msgSender = _msgSender();
for (uint256 i; i < tokens.length; i++) {
address tokenAddress = tokens[i];
uint128 wad = _affiliateBalance[msgSender][tokenAddress];
_affiliateBalance[msgSender][tokenAddress] = 0;
if (wad == 0) {
revert BalanceEmpty();
}
if (tokenAddress == address(0)) {
bool success = false;
(success, ) = msgSender.call{ value: wad }("");
if (!success) {
revert TransferFailed();
}
} else {
IERC20 erc20Token = IERC20(tokenAddress);
erc20Token.safeTransfer(msgSender, wad);
}
emit Withdrawal(msgSender, tokenAddress, wad);
}
}
function withdrawTokens(
PayoutConfig storage payoutConfig,
mapping(address => uint128) storage _ownerBalance,
address owner,
address[] calldata tokens
) public {
address msgSender = _msgSender();
for (uint256 i; i < tokens.length; i++) {
address tokenAddress = tokens[i];
uint128 wad;
if (
msgSender == owner ||
msgSender == PLATFORM ||
msgSender == payoutConfig.partner ||
msgSender == payoutConfig.superAffiliate ||
msgSender == payoutConfig.ownerAltPayout
) {
wad = _ownerBalance[tokenAddress];
_ownerBalance[tokenAddress] = 0;
} else {
revert NotShareholder();
}
if (wad == 0) {
revert BalanceEmpty();
}
address ownerPayout = owner;
if (payoutConfig.ownerAltPayout != address(0)) {
ownerPayout = payoutConfig.ownerAltPayout;
}
uint256 ownerShare = (uint256(wad) * payoutConfig.ownerBps) / 10000;
uint256 remainingShare = wad - ownerShare;
if (tokenAddress == address(0)) {
(bool success, ) = payable(ownerPayout).call{ value: ownerShare }("");
if (!success) revert TransferFailed();
} else {
IERC20(tokenAddress).safeTransfer(ownerPayout, ownerShare);
}
address[] memory recipients = new address[](3);
recipients[0] = PLATFORM;
recipients[1] = payoutConfig.partner;
recipients[2] = payoutConfig.superAffiliate;
uint16[] memory splits = new uint16[](3);
uint16 remainingBps = 10000 - payoutConfig.ownerBps;
splits[1] = uint16((uint256(payoutConfig.partnerBps) * 10000) / remainingBps);
splits[2] = uint16((uint256(payoutConfig.superAffiliateBps) * 10000) / remainingBps);
splits[0] = 10000 - splits[1] - splits[2];
if (tokenAddress == address(0)) {
ArchetypePayouts(PAYOUTS).updateBalances{ value: remainingShare }(
remainingShare,
tokenAddress,
recipients,
splits
);
} else {
ArchetypePayouts(PAYOUTS).updateBalances(
remainingShare,
tokenAddress,
recipients,
splits
);
}
emit Withdrawal(msgSender, tokenAddress, wad);
}
}
function validateAffiliate(
address affiliate,
bytes calldata signature,
address affiliateSigner
) public view {
bytes32 signedMessagehash = ECDSA.toEthSignedMessageHash(
keccak256(abi.encodePacked(affiliate))
);
address signer = ECDSA.recover(signedMessagehash, signature);
if (signer != affiliateSigner) {
revert InvalidSignature();
}
}
function verify(
Auth calldata auth,
address tokenAddress,
address account
) public pure returns (bool) {
// keys 0-255 and tokenAddress are public
if (uint256(auth.key) <= 0xff || auth.key == keccak256(abi.encodePacked(tokenAddress))) {
return true;
}
return MerkleProofLib.verify(auth.proof, auth.key, keccak256(abi.encodePacked(account)));
}
function _msgSender() internal view returns (address) {
return msg.sender == BATCH ? tx.origin : msg.sender;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// ArchetypePayouts v0.7.0
//
// d8888 888 888
// d88888 888 888
// d88P888 888 888
// d88P 888 888d888 .d8888b 88888b. .d88b. 888888 888 888 88888b. .d88b.
// d88P 888 888P" d88P" 888 "88b d8P Y8b 888 888 888 888 "88b d8P Y8b
// d88P 888 888 888 888 888 88888888 888 888 888 888 888 88888888
// d8888888888 888 Y88b. 888 888 Y8b. Y88b. Y88b 888 888 d88P Y8b.
// d88P 888 888 "Y8888P 888 888 "Y8888 "Y888 "Y88888 88888P" "Y8888
// 888 888
// Y8b d88P 888
//
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
using SafeERC20 for IERC20;
error InvalidLength();
error InvalidSplitShares();
error TransferFailed();
error BalanceEmpty();
error NotApprovedToWithdraw();
contract ArchetypePayouts {
event Withdrawal(address indexed src, address token, uint256 wad);
event FundsAdded(address indexed recipient, address token, uint256 amount);
mapping(address => mapping(address => uint256)) private _balance;
mapping(address => mapping(address => bool)) private _approvals;
function updateBalances(
uint256 totalAmount,
address token,
address[] calldata recipients,
uint16[] calldata splits
) public payable {
if (recipients.length != splits.length) {
revert InvalidLength();
}
uint256 totalShares = 0;
for (uint256 i = 0; i < splits.length; i++) {
totalShares += splits[i];
}
if (totalShares != 10000) {
revert InvalidSplitShares();
}
if (token == address(0)) {
// ETH payments
uint256 totalReceived = msg.value;
for (uint256 i = 0; i < recipients.length; i++) {
if (splits[i] > 0) {
uint256 amountToAdd = (totalReceived * splits[i]) / 10000;
_balance[recipients[i]][token] += amountToAdd;
emit FundsAdded(recipients[i], token, amountToAdd);
}
}
} else {
// ERC20 payments
IERC20 paymentToken = IERC20(token);
paymentToken.safeTransferFrom(msg.sender, address(this), totalAmount);
for (uint256 i = 0; i < recipients.length; i++) {
if (splits[i] > 0) {
uint256 amountToAdd = (totalAmount * splits[i]) / 10000;
_balance[recipients[i]][token] += amountToAdd;
emit FundsAdded(recipients[i], token, amountToAdd);
}
}
}
}
function withdraw() external {
address msgSender = msg.sender;
_withdraw(msgSender, msgSender, address(0));
}
function withdrawTokens(address[] memory tokens) external {
address msgSender = msg.sender;
for (uint256 i = 0; i < tokens.length; i++) {
_withdraw(msgSender, msgSender, tokens[i]);
}
}
function withdrawFrom(address from, address to) public {
if (from != msg.sender && !_approvals[from][to]) {
revert NotApprovedToWithdraw();
}
_withdraw(from, to, address(0));
}
function withdrawTokensFrom(
address from,
address to,
address[] memory tokens
) public {
if (from != msg.sender && !_approvals[from][to]) {
revert NotApprovedToWithdraw();
}
for (uint256 i = 0; i < tokens.length; i++) {
_withdraw(from, to, tokens[i]);
}
}
function _withdraw(
address from,
address to,
address token
) internal {
uint256 wad;
wad = _balance[from][token];
_balance[from][token] = 0;
if (wad == 0) {
revert BalanceEmpty();
}
if (token == address(0)) {
bool success = false;
(success, ) = to.call{ value: wad }("");
if (!success) {
revert TransferFailed();
}
} else {
IERC20 erc20Token = IERC20(token);
erc20Token.safeTransfer(to, wad);
}
emit Withdrawal(from, token, wad);
}
function approveWithdrawal(address delegate, bool approved) external {
_approvals[msg.sender][delegate] = approved;
}
function isApproved(address from, address delegate) external view returns (bool) {
return _approvals[from][delegate];
}
function balance(address recipient) external view returns (uint256) {
return _balance[recipient][address(0)];
}
function balanceToken(address recipient, address token) external view returns (uint256) {
return _balance[recipient][token];
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Gas optimized ECDSA wrapper.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
///
/// @dev Note:
/// - The recovery functions use the ecrecover precompile (0x1).
/// - As of Solady version 0.0.68, the `recover` variants will revert upon recovery failure.
/// This is for more safety by default.
/// Use the `tryRecover` variants if you need to get the zero address back
/// upon recovery failure instead.
/// - As of Solady version 0.0.134, all `bytes signature` variants accept both
/// regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.
/// See: https://eips.ethereum.org/EIPS/eip-2098
/// This is for calldata efficiency on smart accounts prevalent on L2s.
///
/// WARNING! Do NOT directly use signatures as unique identifiers:
/// - The recovery operations do NOT check if a signature is non-malleable.
/// - Use a nonce in the digest to prevent replay attacks on the same contract.
/// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.
/// EIP-712 also enables readable signing of typed data for better user safety.
/// - If you need a unique hash from a signature, please use the `canonicalHash` functions.
library ECDSA {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The order of the secp256k1 elliptic curve.
uint256 internal constant N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141;
/// @dev `N/2 + 1`. Used for checking the malleability of the signature.
uint256 private constant _HALF_N_PLUS_1 =
0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The signature is invalid.
error InvalidSignature();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RECOVERY OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function recover(bytes32 hash, bytes memory signature) internal view returns (address result) {
/// @solidity memory-safe-assembly
assembly {
result := 1
let m := mload(0x40) // Cache the free memory pointer.
for {} 1 {} {
mstore(0x00, hash)
mstore(0x40, mload(add(signature, 0x20))) // `r`.
if eq(mload(signature), 64) {
let vs := mload(add(signature, 0x40))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
break
}
if eq(mload(signature), 65) {
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
mstore(0x60, mload(add(signature, 0x40))) // `s`.
break
}
result := 0
break
}
result :=
mload(
staticcall(
gas(), // Amount of gas left for the transaction.
result, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x01, // Start of output.
0x20 // Size of output.
)
)
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if iszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function recoverCalldata(bytes32 hash, bytes calldata signature)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
result := 1
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
for {} 1 {} {
if eq(signature.length, 64) {
let vs := calldataload(add(signature.offset, 0x20))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, calldataload(signature.offset)) // `r`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
break
}
if eq(signature.length, 65) {
mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
break
}
result := 0
break
}
result :=
mload(
staticcall(
gas(), // Amount of gas left for the transaction.
result, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x01, // Start of output.
0x20 // Size of output.
)
)
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if iszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the EIP-2098 short form signature defined by `r` and `vs`.
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, r)
mstore(0x60, shr(1, shl(1, vs))) // `s`.
result :=
mload(
staticcall(
gas(), // Amount of gas left for the transaction.
1, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x01, // Start of output.
0x20 // Size of output.
)
)
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if iszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the signature defined by `v`, `r`, `s`.
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, and(v, 0xff))
mstore(0x40, r)
mstore(0x60, s)
result :=
mload(
staticcall(
gas(), // Amount of gas left for the transaction.
1, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x01, // Start of output.
0x20 // Size of output.
)
)
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
if iszero(returndatasize()) {
mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
revert(0x1c, 0x04)
}
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* TRY-RECOVER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// WARNING!
// These functions will NOT revert upon recovery failure.
// Instead, they will return the zero address upon recovery failure.
// It is critical that the returned address is NEVER compared against
// a zero address (e.g. an uninitialized address variable).
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function tryRecover(bytes32 hash, bytes memory signature)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
result := 1
let m := mload(0x40) // Cache the free memory pointer.
for {} 1 {} {
mstore(0x00, hash)
mstore(0x40, mload(add(signature, 0x20))) // `r`.
if eq(mload(signature), 64) {
let vs := mload(add(signature, 0x40))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
break
}
if eq(mload(signature), 65) {
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
mstore(0x60, mload(add(signature, 0x40))) // `s`.
break
}
result := 0
break
}
pop(
staticcall(
gas(), // Amount of gas left for the transaction.
result, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x40, // Start of output.
0x20 // Size of output.
)
)
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`, and the `signature`.
function tryRecoverCalldata(bytes32 hash, bytes calldata signature)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
result := 1
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
for {} 1 {} {
if eq(signature.length, 64) {
let vs := calldataload(add(signature.offset, 0x20))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, calldataload(signature.offset)) // `r`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
break
}
if eq(signature.length, 65) {
mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
break
}
result := 0
break
}
pop(
staticcall(
gas(), // Amount of gas left for the transaction.
result, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x40, // Start of output.
0x20 // Size of output.
)
)
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the EIP-2098 short form signature defined by `r` and `vs`.
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, r)
mstore(0x60, shr(1, shl(1, vs))) // `s`.
pop(
staticcall(
gas(), // Amount of gas left for the transaction.
1, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x40, // Start of output.
0x20 // Size of output.
)
)
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Recovers the signer's address from a message digest `hash`,
/// and the signature defined by `v`, `r`, `s`.
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internal
view
returns (address result)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x00, hash)
mstore(0x20, and(v, 0xff))
mstore(0x40, r)
mstore(0x60, s)
pop(
staticcall(
gas(), // Amount of gas left for the transaction.
1, // Address of `ecrecover`.
0x00, // Start of input.
0x80, // Size of input.
0x40, // Start of output.
0x20 // Size of output.
)
)
mstore(0x60, 0) // Restore the zero slot.
// `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
result := mload(xor(0x60, returndatasize()))
mstore(0x40, m) // Restore the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an Ethereum Signed Message, created from a `hash`.
/// This produces a hash corresponding to the one signed with the
/// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign)
/// JSON-RPC method as part of EIP-191.
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, hash) // Store into scratch space for keccak256.
mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
}
}
/// @dev Returns an Ethereum Signed Message, created from `s`.
/// This produces a hash corresponding to the one signed with the
/// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign)
/// JSON-RPC method as part of EIP-191.
/// Note: Supports lengths of `s` up to 999999 bytes.
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let sLength := mload(s)
let o := 0x20
mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
mstore(0x00, 0x00)
// Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
for { let temp := sLength } 1 {} {
o := sub(o, 1)
mstore8(o, add(48, mod(temp, 10)))
temp := div(temp, 10)
if iszero(temp) { break }
}
let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
// Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
mstore(s, sLength) // Restore the length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CANONICAL HASH FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// The following functions returns the hash of the signature in it's canonicalized format,
// which is the 65-byte `abi.encodePacked(r, s, uint8(v))`, where `v` is either 27 or 28.
// If `s` is greater than `N / 2` then it will be converted to `N - s`
// and the `v` value will be flipped.
// If the signature has an invalid length, or if `v` is invalid,
// a uniquely corrupt hash will be returned.
// These functions are useful for "poor-mans-VRF".
/// @dev Returns the canonical hash of `signature`.
function canonicalHash(bytes memory signature) internal pure returns (bytes32 result) {
// @solidity memory-safe-assembly
assembly {
let l := mload(signature)
for {} 1 {} {
mstore(0x00, mload(add(signature, 0x20))) // `r`.
let s := mload(add(signature, 0x40))
let v := mload(add(signature, 0x41))
if eq(l, 64) {
v := add(shr(255, s), 27)
s := shr(1, shl(1, s))
}
if iszero(lt(s, _HALF_N_PLUS_1)) {
v := xor(v, 7)
s := sub(N, s)
}
mstore(0x21, v)
mstore(0x20, s)
result := keccak256(0x00, 0x41)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
break
}
// If the length is neither 64 nor 65, return a uniquely corrupted hash.
if iszero(lt(sub(l, 64), 2)) {
// `bytes4(keccak256("InvalidSignatureLength"))`.
result := xor(keccak256(add(signature, 0x20), l), 0xd62f1ab2)
}
}
}
/// @dev Returns the canonical hash of `signature`.
function canonicalHashCalldata(bytes calldata signature)
internal
pure
returns (bytes32 result)
{
// @solidity memory-safe-assembly
assembly {
let l := signature.length
for {} 1 {} {
mstore(0x00, calldataload(signature.offset)) // `r`.
let s := calldataload(add(signature.offset, 0x20))
let v := calldataload(add(signature.offset, 0x21))
if eq(l, 64) {
v := add(shr(255, s), 27)
s := shr(1, shl(1, s))
}
if iszero(lt(s, _HALF_N_PLUS_1)) {
v := xor(v, 7)
s := sub(N, s)
}
mstore(0x21, v)
mstore(0x20, s)
result := keccak256(0x00, 0x41)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
break
}
// If the length is neither 64 nor 65, return a uniquely corrupted hash.
if iszero(lt(sub(l, 64), 2)) {
calldatacopy(mload(0x40), signature.offset, l)
// `bytes4(keccak256("InvalidSignatureLength"))`.
result := xor(keccak256(mload(0x40), l), 0xd62f1ab2)
}
}
}
/// @dev Returns the canonical hash of `signature`.
function canonicalHash(bytes32 r, bytes32 vs) internal pure returns (bytes32 result) {
// @solidity memory-safe-assembly
assembly {
mstore(0x00, r) // `r`.
let v := add(shr(255, vs), 27)
let s := shr(1, shl(1, vs))
mstore(0x21, v)
mstore(0x20, s)
result := keccak256(0x00, 0x41)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
}
}
/// @dev Returns the canonical hash of `signature`.
function canonicalHash(uint8 v, bytes32 r, bytes32 s) internal pure returns (bytes32 result) {
// @solidity memory-safe-assembly
assembly {
mstore(0x00, r) // `r`.
if iszero(lt(s, _HALF_N_PLUS_1)) {
v := xor(v, 7)
s := sub(N, s)
}
mstore(0x21, v)
mstore(0x20, s)
result := keccak256(0x00, 0x41)
mstore(0x21, 0) // Restore the overwritten part of the free memory pointer.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EMPTY CALLDATA HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an empty calldata bytes.
function emptySignature() internal pure returns (bytes calldata signature) {
/// @solidity memory-safe-assembly
assembly {
signature.length := 0
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol)
library MerkleProofLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MERKLE PROOF VERIFICATION OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`.
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf)
internal
pure
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
if mload(proof) {
// Initialize `offset` to the offset of `proof` elements in memory.
let offset := add(proof, 0x20)
// Left shift by 5 is equivalent to multiplying by 0x20.
let end := add(offset, shl(5, mload(proof)))
// Iterate over proof elements to compute root hash.
for {} 1 {} {
// Slot of `leaf` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(leaf, mload(offset)))
// Store elements to hash contiguously in scratch space.
// Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes.
mstore(scratch, leaf)
mstore(xor(scratch, 0x20), mload(offset))
// Reuse `leaf` to store the hash to reduce stack operations.
leaf := keccak256(0x00, 0x40)
offset := add(offset, 0x20)
if iszero(lt(offset, end)) { break }
}
}
isValid := eq(leaf, root)
}
}
/// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`.
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf)
internal
pure
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
if proof.length {
// Left shift by 5 is equivalent to multiplying by 0x20.
let end := add(proof.offset, shl(5, proof.length))
// Initialize `offset` to the offset of `proof` in the calldata.
let offset := proof.offset
// Iterate over proof elements to compute root hash.
for {} 1 {} {
// Slot of `leaf` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(leaf, calldataload(offset)))
// Store elements to hash contiguously in scratch space.
// Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes.
mstore(scratch, leaf)
mstore(xor(scratch, 0x20), calldataload(offset))
// Reuse `leaf` to store the hash to reduce stack operations.
leaf := keccak256(0x00, 0x40)
offset := add(offset, 0x20)
if iszero(lt(offset, end)) { break }
}
}
isValid := eq(leaf, root)
}
}
/// @dev Returns whether all `leaves` exist in the Merkle tree with `root`,
/// given `proof` and `flags`.
///
/// Note:
/// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length`
/// will always return false.
/// - The sum of the lengths of `proof` and `leaves` must never overflow.
/// - Any non-zero word in the `flags` array is treated as true.
/// - The memory offset of `proof` must be non-zero
/// (i.e. `proof` is not pointing to the scratch space).
function verifyMultiProof(
bytes32[] memory proof,
bytes32 root,
bytes32[] memory leaves,
bool[] memory flags
) internal pure returns (bool isValid) {
// Rebuilds the root by consuming and producing values on a queue.
// The queue starts with the `leaves` array, and goes into a `hashes` array.
// After the process, the last element on the queue is verified
// to be equal to the `root`.
//
// The `flags` array denotes whether the sibling
// should be popped from the queue (`flag == true`), or
// should be popped from the `proof` (`flag == false`).
/// @solidity memory-safe-assembly
assembly {
// Cache the lengths of the arrays.
let leavesLength := mload(leaves)
let proofLength := mload(proof)
let flagsLength := mload(flags)
// Advance the pointers of the arrays to point to the data.
leaves := add(0x20, leaves)
proof := add(0x20, proof)
flags := add(0x20, flags)
// If the number of flags is correct.
for {} eq(add(leavesLength, proofLength), add(flagsLength, 1)) {} {
// For the case where `proof.length + leaves.length == 1`.
if iszero(flagsLength) {
// `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`.
isValid := eq(mload(xor(leaves, mul(xor(proof, leaves), proofLength))), root)
break
}
// The required final proof offset if `flagsLength` is not zero, otherwise zero.
let proofEnd := add(proof, shl(5, proofLength))
// We can use the free memory space for the queue.
// We don't need to allocate, since the queue is temporary.
let hashesFront := mload(0x40)
// Copy the leaves into the hashes.
// Sometimes, a little memory expansion costs less than branching.
// Should cost less, even with a high free memory offset of 0x7d00.
leavesLength := shl(5, leavesLength)
for { let i := 0 } iszero(eq(i, leavesLength)) { i := add(i, 0x20) } {
mstore(add(hashesFront, i), mload(add(leaves, i)))
}
// Compute the back of the hashes.
let hashesBack := add(hashesFront, leavesLength)
// This is the end of the memory for the queue.
// We recycle `flagsLength` to save on stack variables (sometimes save gas).
flagsLength := add(hashesBack, shl(5, flagsLength))
for {} 1 {} {
// Pop from `hashes`.
let a := mload(hashesFront)
// Pop from `hashes`.
let b := mload(add(hashesFront, 0x20))
hashesFront := add(hashesFront, 0x40)
// If the flag is false, load the next proof,
// else, pops from the queue.
if iszero(mload(flags)) {
// Loads the next proof.
b := mload(proof)
proof := add(proof, 0x20)
// Unpop from `hashes`.
hashesFront := sub(hashesFront, 0x20)
}
// Advance to the next flag.
flags := add(flags, 0x20)
// Slot of `a` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(a, b))
// Hash the scratch space and push the result onto the queue.
mstore(scratch, a)
mstore(xor(scratch, 0x20), b)
mstore(hashesBack, keccak256(0x00, 0x40))
hashesBack := add(hashesBack, 0x20)
if iszero(lt(hashesBack, flagsLength)) { break }
}
isValid :=
and(
// Checks if the last value in the queue is same as the root.
eq(mload(sub(hashesBack, 0x20)), root),
// And whether all the proofs are used, if required.
eq(proofEnd, proof)
)
break
}
}
}
/// @dev Returns whether all `leaves` exist in the Merkle tree with `root`,
/// given `proof` and `flags`.
///
/// Note:
/// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length`
/// will always return false.
/// - Any non-zero word in the `flags` array is treated as true.
/// - The calldata offset of `proof` must be non-zero
/// (i.e. `proof` is from a regular Solidity function with a 4-byte selector).
function verifyMultiProofCalldata(
bytes32[] calldata proof,
bytes32 root,
bytes32[] calldata leaves,
bool[] calldata flags
) internal pure returns (bool isValid) {
// Rebuilds the root by consuming and producing values on a queue.
// The queue starts with the `leaves` array, and goes into a `hashes` array.
// After the process, the last element on the queue is verified
// to be equal to the `root`.
//
// The `flags` array denotes whether the sibling
// should be popped from the queue (`flag == true`), or
// should be popped from the `proof` (`flag == false`).
/// @solidity memory-safe-assembly
assembly {
// If the number of flags is correct.
for {} eq(add(leaves.length, proof.length), add(flags.length, 1)) {} {
// For the case where `proof.length + leaves.length == 1`.
if iszero(flags.length) {
// `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`.
// forgefmt: disable-next-item
isValid := eq(
calldataload(
xor(leaves.offset, mul(xor(proof.offset, leaves.offset), proof.length))
),
root
)
break
}
// The required final proof offset if `flagsLength` is not zero, otherwise zero.
let proofEnd := add(proof.offset, shl(5, proof.length))
// We can use the free memory space for the queue.
// We don't need to allocate, since the queue is temporary.
let hashesFront := mload(0x40)
// Copy the leaves into the hashes.
// Sometimes, a little memory expansion costs less than branching.
// Should cost less, even with a high free memory offset of 0x7d00.
calldatacopy(hashesFront, leaves.offset, shl(5, leaves.length))
// Compute the back of the hashes.
let hashesBack := add(hashesFront, shl(5, leaves.length))
// This is the end of the memory for the queue.
// We recycle `flagsLength` to save on stack variables (sometimes save gas).
flags.length := add(hashesBack, shl(5, flags.length))
// We don't need to make a copy of `proof.offset` or `flags.offset`,
// as they are pass-by-value (this trick may not always save gas).
for {} 1 {} {
// Pop from `hashes`.
let a := mload(hashesFront)
// Pop from `hashes`.
let b := mload(add(hashesFront, 0x20))
hashesFront := add(hashesFront, 0x40)
// If the flag is false, load the next proof,
// else, pops from the queue.
if iszero(calldataload(flags.offset)) {
// Loads the next proof.
b := calldataload(proof.offset)
proof.offset := add(proof.offset, 0x20)
// Unpop from `hashes`.
hashesFront := sub(hashesFront, 0x20)
}
// Advance to the next flag offset.
flags.offset := add(flags.offset, 0x20)
// Slot of `a` in scratch space.
// If the condition is true: 0x20, otherwise: 0x00.
let scratch := shl(5, gt(a, b))
// Hash the scratch space and push the result onto the queue.
mstore(scratch, a)
mstore(xor(scratch, 0x20), b)
mstore(hashesBack, keccak256(0x00, 0x40))
hashesBack := add(hashesBack, 0x20)
if iszero(lt(hashesBack, flags.length)) { break }
}
isValid :=
and(
// Checks if the last value in the queue is same as the root.
eq(mload(sub(hashesBack, 0x20)), root),
// And whether all the proofs are used, if required.
eq(proofEnd, proof.offset)
)
break
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EMPTY CALLDATA HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an empty calldata bytes32 array.
function emptyProof() internal pure returns (bytes32[] calldata proof) {
/// @solidity memory-safe-assembly
assembly {
proof.length := 0
}
}
/// @dev Returns an empty calldata bytes32 array.
function emptyLeaves() internal pure returns (bytes32[] calldata leaves) {
/// @solidity memory-safe-assembly
assembly {
leaves.length := 0
}
}
/// @dev Returns an empty calldata bool array.
function emptyFlags() internal pure returns (bool[] calldata flags) {
/// @solidity memory-safe-assembly
assembly {
flags.length := 0
}
}
}{
"optimizer": {
"enabled": true,
"runs": 1
},
"metadata": {
"useLiteralContent": true
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"BalanceEmpty","type":"error"},{"inputs":[],"name":"Erc20BalanceTooLow","type":"error"},{"inputs":[],"name":"ExcessiveEthSent","type":"error"},{"inputs":[],"name":"InsufficientEthSent","type":"error"},{"inputs":[],"name":"InvalidReferral","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidTokenId","type":"error"},{"inputs":[],"name":"ListMaxSupplyExceeded","type":"error"},{"inputs":[],"name":"MaxBatchSizeExceeded","type":"error"},{"inputs":[],"name":"MaxSupplyExceeded","type":"error"},{"inputs":[],"name":"MintEnded","type":"error"},{"inputs":[],"name":"MintNotYetStarted","type":"error"},{"inputs":[],"name":"MintingPaused","type":"error"},{"inputs":[],"name":"NotApprovedToTransfer","type":"error"},{"inputs":[],"name":"NotShareholder","type":"error"},{"inputs":[],"name":"NumberOfMintsExceeded","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"WalletUnauthorizedToMint","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"cid","type":"bytes32"}],"name":"Invited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"affiliate","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint128","name":"wad","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"numMints","type":"uint256"}],"name":"Referral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint128","name":"wad","type":"uint128"}],"name":"Withdrawal","type":"event"},{"inputs":[{"internalType":"address","name":"affiliate","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"affiliateSigner","type":"address"}],"name":"validateAffiliate","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"internalType":"struct Auth","name":"auth","type":"tuple"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"verify","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
6121ce61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100775760003560e01c8063140fbc851461007c5780632a70e5821461009e57806332cef8f0146100c65780633c367f7e146100e657806340fe1ac7146100f9578063704c38fc1461010c5780638e1ab8661461012d575b600080fd5b81801561008857600080fd5b5061009c610097366004611938565b61014d565b005b6100b16100ac3660046119b7565b6102f1565b60405190151581526020015b60405180910390f35b8180156100d257600080fd5b5061009c6100e1366004611a14565b6103b4565b61009c6100f4366004611c39565b610573565b61009c610107366004611cf6565b610c76565b61011f61011a366004611d6b565b610d4d565b6040519081526020016100bd565b81801561013957600080fd5b5061009c610148366004611dc8565b610f93565b600061015761154e565b905060005b828110156102ea57600084848381811061017857610178611e2f565b905060200201602081019061018d9190611e45565b6001600160a01b03848116600090815260208981526040808320938516835292905290812080546001600160801b031981169091559192506001600160801b03909116908190036101f1576040516321cd723f60e21b815260040160405180910390fd5b6001600160a01b038216610284576000846001600160a01b0316826001600160801b031660405160006040518083038185875af1925050503d8060008114610255576040519150601f19603f3d011682016040523d82523d6000602084013e61025a565b606091505b5050809150508061027e576040516312171d8360e31b815260040160405180910390fd5b506102a4565b816102a26001600160a01b038216866001600160801b038516611575565b505b836001600160a01b031660008051602061217983398151915283836040516102cd929190611e60565b60405180910390a2505080806102e290611e98565b91505061015c565b5050505050565b600060ff843511158061032d5750826040516020016103109190611eb1565b604051602081830303815290604052805190602001208460000135145b1561033a575060016103ad565b6103aa61034a6020860186611ec9565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040518835925061038f91508690602001611eb1565b604051602081830303815290604052805190602001206115dd565b90505b9392505050565b60048701546001600160a01b03908116906000908516156104c8576003880154612710906103ec9062010000900461ffff1685611f12565b6103f69190611f53565b6001600160a01b038087166000908152602089815260408083209387168352929052908120805492935083929091906104399084906001600160801b0316611f79565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550846001600160a01b03167f8abfbe92bb62ff992ef6347c68d007f25a6e5aea2ad2f05e89f3486947cc0b208383876040516104bf939291906001600160a01b039390931683526001600160801b03919091166020830152604082015260600190565b60405180910390a25b6001600160a01b0382166000908152602088905260408120546001600160801b0316906104f58386611fa0565b90506105018183611f79565b6001600160a01b038516600081815260208c90526040902080546001600160801b0319166001600160801b03939093169290921790915515610566578361056461054961154e565b6001600160a01b03831690306001600160801b038a1661161f565b505b5050505050505050505050565b600061057d61154e565b60208401519091506001600160a01b03161561063a5760208301516001600160a01b03167386b82972282dd22348374bc63fd21620f7ed847b14806105db575082600001516001600160a01b031683602001516001600160a01b0316145b806105fb5750806001600160a01b031683602001516001600160a01b0316145b156106195760405163119833d760e11b815260040160405180910390fd5b602083015160018a015461063a9190879087906001600160a01b0316610c76565b60018a0154600160c01b900463ffffffff1660000361066c576040516375ab03ab60e11b815260040160405180910390fd5b60048a01546106869089906001600160a01b0316836102f1565b6106a35760405163d838648f60e01b815260040160405180910390fd5b60018a0154600160801b900463ffffffff164210156106d557604051630e91d3a160e11b815260040160405180910390fd5b60018a015463ffffffff600160801b82048116600160a01b9092041611801561070e575060018a0154600160a01b900463ffffffff1642115b1561072c5760405163124212e560e21b815260040160405180910390fd5b6000805b84604001515181101561077a578460400151818151811061075357610753611e2f565b6020026020010151826107669190611fc0565b91508061077281611e98565b915050610730565b5060018b015460009063ffffffff600160e01b82048116600160c01b909204161015610803576001600160a01b038316600090815260208a815260408083208d3584529091529020546107ce908390611fc0565b60018d0154909150600160c01b900463ffffffff16811115610803576040516315fcbc9d60e01b815260040160405180910390fd5b60018c015463ffffffff600160e01b9091048116101561086257818560a0015161082d9190611fc0565b60018d0154909150600160e01b900463ffffffff168111156108625760405163103f447360e31b815260040160405180910390fd5b5086546000906001600160401b0381111561087f5761087f611ac8565b6040519080825280602002602001820160405280156108a8578160200160208202803683370190505b50905060005b856060015151811015610acc576000866060015182815181106108d3576108d3611e2f565b602002602001015190508d6003018054905060001461097a576000805b8f60030180549050811015610959578f600301818154811061091457610914611e2f565b6000918252602090912060088204015460079091166004026101000a900463ffffffff1683036109475760019150610959565b8061095181611e98565b9150506108f0565b5080610978576040516307ed98ed60e31b815260040160405180910390fd5b505b60028d01610989600183611fd9565b8154811061099957610999611e2f565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1663ffffffff16876040015183815181106109db576109db611e2f565b6020026020010151846001846109f19190611fd9565b81518110610a0157610a01611e2f565b60200260200101518c600185610a179190611fd9565b81548110610a2757610a27611e2f565b9060005260206000200154610a3c9190611fc0565b610a469190611fc0565b1115610a6557604051638a164f6360e01b815260040160405180910390fd5b86604001518281518110610a7b57610a7b611e2f565b602002602001015183600183610a919190611fd9565b81518110610aa157610aa1611e2f565b60200260200101818151610ab59190611fc0565b905250819050610ac481611e98565b9150506108ae565b5060038b015461ffff16821115610af657604051637a7e96df60e01b815260040160405180910390fd5b60048c01546001600160a01b031615610c555760048c810154604051636eb1769f60e11b81526001600160a01b03868116938201939093523060248201529116908590829063dd62ed3e90604401602060405180830381865afa158015610b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b859190611fec565b1015610ba4576040516302df483560e21b815260040160405180910390fd5b6040516370a0823160e01b81526001600160a01b0385811660048301528691908316906370a0823190602401602060405180830381865afa158015610bed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c119190611fec565b1015610c305760405163046abae760e31b815260040160405180910390fd5b3415610c4f576040516301b2422760e61b815260040160405180910390fd5b50610564565b833410156105645760405163f244866f60e01b815260040160405180910390fd5b6000610ccd85604051602001610c8c9190611eb1565b604051602081830303815290604052805190602001206020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b90506000610d118286868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061165d92505050565b9050826001600160a01b0316816001600160a01b031614610d4557604051638baa579f60e01b815260040160405180910390fd5b505050505050565b845460028601546000916001600160801b031690829063ffffffff1615801590610d83575060018801546001600160801b031615155b15610eae57600188015460028901546000916001600160801b0381169163ffffffff90811691610dbc91600160801b9091041642611fd9565b610dc69190612005565b610dd09190612019565b8954909150600160801b90046001600160801b0316831115610e39578854610e0890600160801b90046001600160801b031684611fd9565b811115610e28578854600160801b90046001600160801b03169250610e9c565b610e328184611fd9565b9250610e9c565b8854600160801b90046001600160801b0316831015610e9c578854610e6f908490600160801b90046001600160801b0316611fd9565b811115610e8f578854600160801b90046001600160801b03169250610e9c565b610e998184611fc0565b92505b610ea68784612019565b915050610f5a565b600288015463ffffffff16158015610ed2575060018801546001600160801b031615155b15610f4d576001880154600090610ef39087906001600160801b0316612019565b610efd9084611fc0565b90506002610f0c600189611fd9565b60018b0154610f25908a906001600160801b0316612019565b610f2f9190612019565b610f399190612005565b610f438883612019565b610ea69190611fc0565b610f578683612019565b90505b8315610f8857612710610f7161ffff891683612019565b610f7b9190612005565b610f859082611fd9565b90505b979650505050505050565b6000610f9d61154e565b905060005b82811015611545576000848483818110610fbe57610fbe611e2f565b9050602002016020810190610fd39190611e45565b90506000866001600160a01b0316846001600160a01b0316148061101357506001600160a01b0384167386b82972282dd22348374bc63fd21620f7ed847b145b80611031575088546001600160a01b03858116600160401b90920416145b8061104b575060018901546001600160a01b038581169116145b80611065575060028901546001600160a01b038581169116145b156110a157506001600160a01b038116600090815260208890526040902080546001600160801b031981169091556001600160801b03166110ba565b60405163650a61e160e01b815260040160405180910390fd5b806001600160801b03166000036110e4576040516321cd723f60e21b815260040160405180910390fd5b600289015487906001600160a01b031615611109575060028901546001600160a01b03165b8954600090612710906111299061ffff166001600160801b038616612019565b6111339190612005565b9050600061114a826001600160801b038616611fd9565b90506001600160a01b0385166111d4576000836001600160a01b03168360405160006040518083038185875af1925050503d80600081146111a7576040519150601f19603f3d011682016040523d82523d6000602084013e6111ac565b606091505b50509050806111ce576040516312171d8360e31b815260040160405180910390fd5b506111e8565b6111e86001600160a01b0386168484611575565b60408051600380825260808201909252600091602082016060803683370190505090507386b82972282dd22348374bc63fd21620f7ed847b8160008151811061123357611233611e2f565b6001600160a01b0392831660209182029290920101528d548251600160401b909104909116908290600190811061126c5761126c611e2f565b6001600160a01b03928316602091820292909201015260018e015482519116908290600290811061129f5761129f611e2f565b6001600160a01b039290921660209283029190910182015260408051600380825260808201909252600092909190820160608036833750508f549192506000916112f0915061ffff16612710612030565b8f5490915061ffff8083169161131191600160201b90910416612710612019565b61131b9190612005565b8260018151811061132e5761132e611e2f565b61ffff92831660209182029290920101528f548282169161135991600160301b900416612710612019565b6113639190612005565b8260028151811061137657611376611e2f565b602002602001019061ffff16908161ffff16815250508160028151811061139f5761139f611e2f565b6020026020010151826001815181106113ba576113ba611e2f565b60200260200101516127106113cf9190612030565b6113d99190612030565b826000815181106113ec576113ec611e2f565b61ffff909216602092830291909101909101526001600160a01b038816611486576040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e90869061144f9082908d908990899060040161204b565b6000604051808303818588803b15801561146857600080fd5b505af115801561147c573d6000803e3d6000fd5b50505050506114f9565b6040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e906114c69087908c908890889060040161204b565b600060405180830381600087803b1580156114e057600080fd5b505af11580156114f4573d6000803e3d6000fd5b505050505b896001600160a01b03166000805160206121798339815191528989604051611522929190611e60565b60405180910390a25050505050505050808061153d90611e98565b915050610fa2565b50505050505050565b60003373ea49e7be310716da66725c84a5127d2f6a202eaf1461157057503390565b503290565b6040516001600160a01b0383166024820152604481018290526115d890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526116ee565b505050565b60008351156116185760208401845160051b81015b8151841160051b9384528151602094851852604060002093909101908082106115f25750505b5014919050565b6040516001600160a01b03808516602483015283166044820152606481018290526116579085906323b872dd60e01b906084016115a1565b50505050565b604051600190836000526020830151604052604083510361169957604083015160ff81901c601b016020526001600160ff1b03166060526116bf565b60418351036116ba57606083015160001a60205260408301516060526116bf565b600091505b6020600160806000855afa5191503d6116e057638baa579f6000526004601cfd5b600060605260405292915050565b6000611743826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166117c89092919063ffffffff16565b905080516000148061176457508080602001905181019061176491906120e8565b6115d85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084015b60405180910390fd5b60606103aa848460008585600080866001600160a01b031685876040516117ef9190612129565b60006040518083038185875af1925050503d806000811461182c576040519150601f19603f3d011682016040523d82523d6000602084013e611831565b606091505b50915091506118428783838761184f565b925050505b949350505050565b606083156118be5782516000036118b7576001600160a01b0385163b6118b75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016117bf565b5081611847565b61184783838151156118d35781518083602001fd5b8060405162461bcd60e51b81526004016117bf9190612145565b60008083601f8401126118ff57600080fd5b5081356001600160401b0381111561191657600080fd5b6020830191508360208260051b850101111561193157600080fd5b9250929050565b60008060006040848603121561194d57600080fd5b8335925060208401356001600160401b0381111561196a57600080fd5b611976868287016118ed565b9497909650939450505050565b60006040828403121561199557600080fd5b50919050565b80356001600160a01b03811681146119b257600080fd5b919050565b6000806000606084860312156119cc57600080fd5b83356001600160401b038111156119e257600080fd5b6119ee86828701611983565b9350506119fd6020850161199b565b9150611a0b6040850161199b565b90509250925092565b600080600080600080600060e0888a031215611a2f57600080fd5b87359650602088013595506040880135945060608801359350611a546080890161199b565b925060a0880135915060c08801356001600160801b0381168114611a7757600080fd5b8091505092959891949750929550565b60008083601f840112611a9957600080fd5b5081356001600160401b03811115611ab057600080fd5b60208301915083602082850101111561193157600080fd5b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b0381118282101715611b0057611b00611ac8565b60405290565b600082601f830112611b1757600080fd5b813560206001600160401b0380831115611b3357611b33611ac8565b8260051b604051601f19603f83011681018181108482111715611b5857611b58611ac8565b604052938452858101830193838101925087851115611b7657600080fd5b83870191505b84821015610f8857813583529183019190830190611b7c565b600060c08284031215611ba757600080fd5b611baf611ade565b9050611bba8261199b565b8152611bc86020830161199b565b602082015260408201356001600160401b0380821115611be757600080fd5b611bf385838601611b06565b60408401526060840135915080821115611c0c57600080fd5b50611c1984828501611b06565b6060830152506080820135608082015260a082013560a082015292915050565b60008060008060008060008060006101008a8c031215611c5857600080fd5b8935985060208a0135975060408a01356001600160401b0380821115611c7d57600080fd5b611c898d838e01611983565b985060608c0135975060808c0135965060a08c0135915080821115611cad57600080fd5b611cb98d838e01611a87565b909650945060c08c0135915080821115611cd257600080fd5b50611cdf8c828d01611b95565b92505060e08a013590509295985092959850929598565b60008060008060608587031215611d0c57600080fd5b611d158561199b565b935060208501356001600160401b03811115611d3057600080fd5b611d3c87828801611a87565b9094509250611d4f90506040860161199b565b905092959194509250565b8015158114611d6857600080fd5b50565b600080600080600060a08688031215611d8357600080fd5b85359450602086013561ffff81168114611d9c57600080fd5b935060408601359250606086013591506080860135611dba81611d5a565b809150509295509295909350565b600080600080600060808688031215611de057600080fd5b8535945060208601359350611df76040870161199b565b925060608601356001600160401b03811115611e1257600080fd5b611e1e888289016118ed565b969995985093965092949392505050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611e5757600080fd5b6103ad8261199b565b6001600160a01b039290921682526001600160801b0316602082015260400190565b634e487b7160e01b600052601160045260246000fd5b600060018201611eaa57611eaa611e82565b5060010190565b60609190911b6001600160601b031916815260140190565b6000808335601e19843603018112611ee057600080fd5b8301803591506001600160401b03821115611efa57600080fd5b6020019150600581901b360382131561193157600080fd5b6001600160801b03818116838216028082169190828114611f3557611f35611e82565b505092915050565b634e487b7160e01b600052601260045260246000fd5b60006001600160801b0383811680611f6d57611f6d611f3d565b92169190910492915050565b6001600160801b03818116838216019080821115611f9957611f99611e82565b5092915050565b6001600160801b03828116828216039080821115611f9957611f99611e82565b80820180821115611fd357611fd3611e82565b92915050565b81810381811115611fd357611fd3611e82565b600060208284031215611ffe57600080fd5b5051919050565b60008261201457612014611f3d565b500490565b8082028115828204841417611fd357611fd3611e82565b61ffff828116828216039080821115611f9957611f99611e82565b600060808201868352602060018060a01b03808816828601526080604086015282875180855260a087019150838901945060005b8181101561209d57855184168352948401949184019160010161207f565b5050858103606087015286518082529083019350905081860160005b828110156120d957815161ffff16855293830193908301906001016120b9565b50929998505050505050505050565b6000602082840312156120fa57600080fd5b81516103ad81611d5a565b60005b83811015612120578181015183820152602001612108565b50506000910152565b6000825161213b818460208701612105565b9190910192915050565b6020815260008251806020840152612164816040850160208701612105565b601f01601f1916919091016040019291505056fe02128911bc7070fd6c100b116c2dd9a3bb6bf132d5259a65ca8d0c86ccd78f49a264697066735822122060e1d4110ce3426b868a7d3302993770a5f0407da8fa9292e56734efc8c0fa6b64736f6c63430008140033
Deployed Bytecode
0x73aeb8ec71de076d8ad24a85daccb161ca640415f030146080604052600436106100775760003560e01c8063140fbc851461007c5780632a70e5821461009e57806332cef8f0146100c65780633c367f7e146100e657806340fe1ac7146100f9578063704c38fc1461010c5780638e1ab8661461012d575b600080fd5b81801561008857600080fd5b5061009c610097366004611938565b61014d565b005b6100b16100ac3660046119b7565b6102f1565b60405190151581526020015b60405180910390f35b8180156100d257600080fd5b5061009c6100e1366004611a14565b6103b4565b61009c6100f4366004611c39565b610573565b61009c610107366004611cf6565b610c76565b61011f61011a366004611d6b565b610d4d565b6040519081526020016100bd565b81801561013957600080fd5b5061009c610148366004611dc8565b610f93565b600061015761154e565b905060005b828110156102ea57600084848381811061017857610178611e2f565b905060200201602081019061018d9190611e45565b6001600160a01b03848116600090815260208981526040808320938516835292905290812080546001600160801b031981169091559192506001600160801b03909116908190036101f1576040516321cd723f60e21b815260040160405180910390fd5b6001600160a01b038216610284576000846001600160a01b0316826001600160801b031660405160006040518083038185875af1925050503d8060008114610255576040519150601f19603f3d011682016040523d82523d6000602084013e61025a565b606091505b5050809150508061027e576040516312171d8360e31b815260040160405180910390fd5b506102a4565b816102a26001600160a01b038216866001600160801b038516611575565b505b836001600160a01b031660008051602061217983398151915283836040516102cd929190611e60565b60405180910390a2505080806102e290611e98565b91505061015c565b5050505050565b600060ff843511158061032d5750826040516020016103109190611eb1565b604051602081830303815290604052805190602001208460000135145b1561033a575060016103ad565b6103aa61034a6020860186611ec9565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040518835925061038f91508690602001611eb1565b604051602081830303815290604052805190602001206115dd565b90505b9392505050565b60048701546001600160a01b03908116906000908516156104c8576003880154612710906103ec9062010000900461ffff1685611f12565b6103f69190611f53565b6001600160a01b038087166000908152602089815260408083209387168352929052908120805492935083929091906104399084906001600160801b0316611f79565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550846001600160a01b03167f8abfbe92bb62ff992ef6347c68d007f25a6e5aea2ad2f05e89f3486947cc0b208383876040516104bf939291906001600160a01b039390931683526001600160801b03919091166020830152604082015260600190565b60405180910390a25b6001600160a01b0382166000908152602088905260408120546001600160801b0316906104f58386611fa0565b90506105018183611f79565b6001600160a01b038516600081815260208c90526040902080546001600160801b0319166001600160801b03939093169290921790915515610566578361056461054961154e565b6001600160a01b03831690306001600160801b038a1661161f565b505b5050505050505050505050565b600061057d61154e565b60208401519091506001600160a01b03161561063a5760208301516001600160a01b03167386b82972282dd22348374bc63fd21620f7ed847b14806105db575082600001516001600160a01b031683602001516001600160a01b0316145b806105fb5750806001600160a01b031683602001516001600160a01b0316145b156106195760405163119833d760e11b815260040160405180910390fd5b602083015160018a015461063a9190879087906001600160a01b0316610c76565b60018a0154600160c01b900463ffffffff1660000361066c576040516375ab03ab60e11b815260040160405180910390fd5b60048a01546106869089906001600160a01b0316836102f1565b6106a35760405163d838648f60e01b815260040160405180910390fd5b60018a0154600160801b900463ffffffff164210156106d557604051630e91d3a160e11b815260040160405180910390fd5b60018a015463ffffffff600160801b82048116600160a01b9092041611801561070e575060018a0154600160a01b900463ffffffff1642115b1561072c5760405163124212e560e21b815260040160405180910390fd5b6000805b84604001515181101561077a578460400151818151811061075357610753611e2f565b6020026020010151826107669190611fc0565b91508061077281611e98565b915050610730565b5060018b015460009063ffffffff600160e01b82048116600160c01b909204161015610803576001600160a01b038316600090815260208a815260408083208d3584529091529020546107ce908390611fc0565b60018d0154909150600160c01b900463ffffffff16811115610803576040516315fcbc9d60e01b815260040160405180910390fd5b60018c015463ffffffff600160e01b9091048116101561086257818560a0015161082d9190611fc0565b60018d0154909150600160e01b900463ffffffff168111156108625760405163103f447360e31b815260040160405180910390fd5b5086546000906001600160401b0381111561087f5761087f611ac8565b6040519080825280602002602001820160405280156108a8578160200160208202803683370190505b50905060005b856060015151811015610acc576000866060015182815181106108d3576108d3611e2f565b602002602001015190508d6003018054905060001461097a576000805b8f60030180549050811015610959578f600301818154811061091457610914611e2f565b6000918252602090912060088204015460079091166004026101000a900463ffffffff1683036109475760019150610959565b8061095181611e98565b9150506108f0565b5080610978576040516307ed98ed60e31b815260040160405180910390fd5b505b60028d01610989600183611fd9565b8154811061099957610999611e2f565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1663ffffffff16876040015183815181106109db576109db611e2f565b6020026020010151846001846109f19190611fd9565b81518110610a0157610a01611e2f565b60200260200101518c600185610a179190611fd9565b81548110610a2757610a27611e2f565b9060005260206000200154610a3c9190611fc0565b610a469190611fc0565b1115610a6557604051638a164f6360e01b815260040160405180910390fd5b86604001518281518110610a7b57610a7b611e2f565b602002602001015183600183610a919190611fd9565b81518110610aa157610aa1611e2f565b60200260200101818151610ab59190611fc0565b905250819050610ac481611e98565b9150506108ae565b5060038b015461ffff16821115610af657604051637a7e96df60e01b815260040160405180910390fd5b60048c01546001600160a01b031615610c555760048c810154604051636eb1769f60e11b81526001600160a01b03868116938201939093523060248201529116908590829063dd62ed3e90604401602060405180830381865afa158015610b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b859190611fec565b1015610ba4576040516302df483560e21b815260040160405180910390fd5b6040516370a0823160e01b81526001600160a01b0385811660048301528691908316906370a0823190602401602060405180830381865afa158015610bed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c119190611fec565b1015610c305760405163046abae760e31b815260040160405180910390fd5b3415610c4f576040516301b2422760e61b815260040160405180910390fd5b50610564565b833410156105645760405163f244866f60e01b815260040160405180910390fd5b6000610ccd85604051602001610c8c9190611eb1565b604051602081830303815290604052805190602001206020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b90506000610d118286868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061165d92505050565b9050826001600160a01b0316816001600160a01b031614610d4557604051638baa579f60e01b815260040160405180910390fd5b505050505050565b845460028601546000916001600160801b031690829063ffffffff1615801590610d83575060018801546001600160801b031615155b15610eae57600188015460028901546000916001600160801b0381169163ffffffff90811691610dbc91600160801b9091041642611fd9565b610dc69190612005565b610dd09190612019565b8954909150600160801b90046001600160801b0316831115610e39578854610e0890600160801b90046001600160801b031684611fd9565b811115610e28578854600160801b90046001600160801b03169250610e9c565b610e328184611fd9565b9250610e9c565b8854600160801b90046001600160801b0316831015610e9c578854610e6f908490600160801b90046001600160801b0316611fd9565b811115610e8f578854600160801b90046001600160801b03169250610e9c565b610e998184611fc0565b92505b610ea68784612019565b915050610f5a565b600288015463ffffffff16158015610ed2575060018801546001600160801b031615155b15610f4d576001880154600090610ef39087906001600160801b0316612019565b610efd9084611fc0565b90506002610f0c600189611fd9565b60018b0154610f25908a906001600160801b0316612019565b610f2f9190612019565b610f399190612005565b610f438883612019565b610ea69190611fc0565b610f578683612019565b90505b8315610f8857612710610f7161ffff891683612019565b610f7b9190612005565b610f859082611fd9565b90505b979650505050505050565b6000610f9d61154e565b905060005b82811015611545576000848483818110610fbe57610fbe611e2f565b9050602002016020810190610fd39190611e45565b90506000866001600160a01b0316846001600160a01b0316148061101357506001600160a01b0384167386b82972282dd22348374bc63fd21620f7ed847b145b80611031575088546001600160a01b03858116600160401b90920416145b8061104b575060018901546001600160a01b038581169116145b80611065575060028901546001600160a01b038581169116145b156110a157506001600160a01b038116600090815260208890526040902080546001600160801b031981169091556001600160801b03166110ba565b60405163650a61e160e01b815260040160405180910390fd5b806001600160801b03166000036110e4576040516321cd723f60e21b815260040160405180910390fd5b600289015487906001600160a01b031615611109575060028901546001600160a01b03165b8954600090612710906111299061ffff166001600160801b038616612019565b6111339190612005565b9050600061114a826001600160801b038616611fd9565b90506001600160a01b0385166111d4576000836001600160a01b03168360405160006040518083038185875af1925050503d80600081146111a7576040519150601f19603f3d011682016040523d82523d6000602084013e6111ac565b606091505b50509050806111ce576040516312171d8360e31b815260040160405180910390fd5b506111e8565b6111e86001600160a01b0386168484611575565b60408051600380825260808201909252600091602082016060803683370190505090507386b82972282dd22348374bc63fd21620f7ed847b8160008151811061123357611233611e2f565b6001600160a01b0392831660209182029290920101528d548251600160401b909104909116908290600190811061126c5761126c611e2f565b6001600160a01b03928316602091820292909201015260018e015482519116908290600290811061129f5761129f611e2f565b6001600160a01b039290921660209283029190910182015260408051600380825260808201909252600092909190820160608036833750508f549192506000916112f0915061ffff16612710612030565b8f5490915061ffff8083169161131191600160201b90910416612710612019565b61131b9190612005565b8260018151811061132e5761132e611e2f565b61ffff92831660209182029290920101528f548282169161135991600160301b900416612710612019565b6113639190612005565b8260028151811061137657611376611e2f565b602002602001019061ffff16908161ffff16815250508160028151811061139f5761139f611e2f565b6020026020010151826001815181106113ba576113ba611e2f565b60200260200101516127106113cf9190612030565b6113d99190612030565b826000815181106113ec576113ec611e2f565b61ffff909216602092830291909101909101526001600160a01b038816611486576040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e90869061144f9082908d908990899060040161204b565b6000604051808303818588803b15801561146857600080fd5b505af115801561147c573d6000803e3d6000fd5b50505050506114f9565b6040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e906114c69087908c908890889060040161204b565b600060405180830381600087803b1580156114e057600080fd5b505af11580156114f4573d6000803e3d6000fd5b505050505b896001600160a01b03166000805160206121798339815191528989604051611522929190611e60565b60405180910390a25050505050505050808061153d90611e98565b915050610fa2565b50505050505050565b60003373ea49e7be310716da66725c84a5127d2f6a202eaf1461157057503390565b503290565b6040516001600160a01b0383166024820152604481018290526115d890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526116ee565b505050565b60008351156116185760208401845160051b81015b8151841160051b9384528151602094851852604060002093909101908082106115f25750505b5014919050565b6040516001600160a01b03808516602483015283166044820152606481018290526116579085906323b872dd60e01b906084016115a1565b50505050565b604051600190836000526020830151604052604083510361169957604083015160ff81901c601b016020526001600160ff1b03166060526116bf565b60418351036116ba57606083015160001a60205260408301516060526116bf565b600091505b6020600160806000855afa5191503d6116e057638baa579f6000526004601cfd5b600060605260405292915050565b6000611743826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166117c89092919063ffffffff16565b905080516000148061176457508080602001905181019061176491906120e8565b6115d85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084015b60405180910390fd5b60606103aa848460008585600080866001600160a01b031685876040516117ef9190612129565b60006040518083038185875af1925050503d806000811461182c576040519150601f19603f3d011682016040523d82523d6000602084013e611831565b606091505b50915091506118428783838761184f565b925050505b949350505050565b606083156118be5782516000036118b7576001600160a01b0385163b6118b75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016117bf565b5081611847565b61184783838151156118d35781518083602001fd5b8060405162461bcd60e51b81526004016117bf9190612145565b60008083601f8401126118ff57600080fd5b5081356001600160401b0381111561191657600080fd5b6020830191508360208260051b850101111561193157600080fd5b9250929050565b60008060006040848603121561194d57600080fd5b8335925060208401356001600160401b0381111561196a57600080fd5b611976868287016118ed565b9497909650939450505050565b60006040828403121561199557600080fd5b50919050565b80356001600160a01b03811681146119b257600080fd5b919050565b6000806000606084860312156119cc57600080fd5b83356001600160401b038111156119e257600080fd5b6119ee86828701611983565b9350506119fd6020850161199b565b9150611a0b6040850161199b565b90509250925092565b600080600080600080600060e0888a031215611a2f57600080fd5b87359650602088013595506040880135945060608801359350611a546080890161199b565b925060a0880135915060c08801356001600160801b0381168114611a7757600080fd5b8091505092959891949750929550565b60008083601f840112611a9957600080fd5b5081356001600160401b03811115611ab057600080fd5b60208301915083602082850101111561193157600080fd5b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b0381118282101715611b0057611b00611ac8565b60405290565b600082601f830112611b1757600080fd5b813560206001600160401b0380831115611b3357611b33611ac8565b8260051b604051601f19603f83011681018181108482111715611b5857611b58611ac8565b604052938452858101830193838101925087851115611b7657600080fd5b83870191505b84821015610f8857813583529183019190830190611b7c565b600060c08284031215611ba757600080fd5b611baf611ade565b9050611bba8261199b565b8152611bc86020830161199b565b602082015260408201356001600160401b0380821115611be757600080fd5b611bf385838601611b06565b60408401526060840135915080821115611c0c57600080fd5b50611c1984828501611b06565b6060830152506080820135608082015260a082013560a082015292915050565b60008060008060008060008060006101008a8c031215611c5857600080fd5b8935985060208a0135975060408a01356001600160401b0380821115611c7d57600080fd5b611c898d838e01611983565b985060608c0135975060808c0135965060a08c0135915080821115611cad57600080fd5b611cb98d838e01611a87565b909650945060c08c0135915080821115611cd257600080fd5b50611cdf8c828d01611b95565b92505060e08a013590509295985092959850929598565b60008060008060608587031215611d0c57600080fd5b611d158561199b565b935060208501356001600160401b03811115611d3057600080fd5b611d3c87828801611a87565b9094509250611d4f90506040860161199b565b905092959194509250565b8015158114611d6857600080fd5b50565b600080600080600060a08688031215611d8357600080fd5b85359450602086013561ffff81168114611d9c57600080fd5b935060408601359250606086013591506080860135611dba81611d5a565b809150509295509295909350565b600080600080600060808688031215611de057600080fd5b8535945060208601359350611df76040870161199b565b925060608601356001600160401b03811115611e1257600080fd5b611e1e888289016118ed565b969995985093965092949392505050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611e5757600080fd5b6103ad8261199b565b6001600160a01b039290921682526001600160801b0316602082015260400190565b634e487b7160e01b600052601160045260246000fd5b600060018201611eaa57611eaa611e82565b5060010190565b60609190911b6001600160601b031916815260140190565b6000808335601e19843603018112611ee057600080fd5b8301803591506001600160401b03821115611efa57600080fd5b6020019150600581901b360382131561193157600080fd5b6001600160801b03818116838216028082169190828114611f3557611f35611e82565b505092915050565b634e487b7160e01b600052601260045260246000fd5b60006001600160801b0383811680611f6d57611f6d611f3d565b92169190910492915050565b6001600160801b03818116838216019080821115611f9957611f99611e82565b5092915050565b6001600160801b03828116828216039080821115611f9957611f99611e82565b80820180821115611fd357611fd3611e82565b92915050565b81810381811115611fd357611fd3611e82565b600060208284031215611ffe57600080fd5b5051919050565b60008261201457612014611f3d565b500490565b8082028115828204841417611fd357611fd3611e82565b61ffff828116828216039080821115611f9957611f99611e82565b600060808201868352602060018060a01b03808816828601526080604086015282875180855260a087019150838901945060005b8181101561209d57855184168352948401949184019160010161207f565b5050858103606087015286518082529083019350905081860160005b828110156120d957815161ffff16855293830193908301906001016120b9565b50929998505050505050505050565b6000602082840312156120fa57600080fd5b81516103ad81611d5a565b60005b83811015612120578181015183820152602001612108565b50506000910152565b6000825161213b818460208701612105565b9190910192915050565b6020815260008251806020840152612164816040850160208701612105565b601f01601f1916919091016040019291505056fe02128911bc7070fd6c100b116c2dd9a3bb6bf132d5259a65ca8d0c86ccd78f49a264697066735822122060e1d4110ce3426b868a7d3302993770a5f0407da8fa9292e56734efc8c0fa6b64736f6c63430008140033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MON
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.