Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
AirdropDistribution
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; import {Math} from "openzeppelin-contracts/utils/math/Math.sol"; import {PausableUpgradeable} from "openzeppelin-contracts-upgradeable/utils/PausableUpgradeable.sol"; import {Initializable} from "openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol"; import {ReentrancyGuardUpgradeable} from "openzeppelin-contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import {CheckAccessControl} from "src/utils/CheckAccessControl.sol"; import {IRegistryAccess} from "src/interfaces/registry/IRegistryAccess.sol"; import {IRegistryContract} from "src/interfaces/registry/IRegistryContract.sol"; import {IAirdropDistribution} from "src/interfaces/airdrop/IAirdropDistribution.sol"; import {IAirdropTaxCollector} from "src/interfaces/airdrop/IAirdropTaxCollector.sol"; import {IUsual} from "src/interfaces/token/IUsual.sol"; import {MerkleProof} from "openzeppelin-contracts/utils/cryptography/MerkleProof.sol"; import { CONTRACT_USUAL, CONTRACT_REGISTRY_ACCESS, CONTRACT_AIRDROP_TAX_COLLECTOR, AIRDROP_VESTING_DURATION_IN_MONTHS, END_OF_EARLY_UNLOCK_PERIOD, AIRDROP_INITIAL_START_TIME, FIRST_AIRDROP_VESTING_CLAIMING_DATE, SECOND_AIRDROP_VESTING_CLAIMING_DATE, THIRD_AIRDROP_VESTING_CLAIMING_DATE, FOURTH_AIRDROP_VESTING_CLAIMING_DATE, FIFTH_AIRDROP_VESTING_CLAIMING_DATE, SIXTH_AIRDROP_VESTING_CLAIMING_DATE, BASIS_POINT_BASE, DEFAULT_ADMIN_ROLE, AIRDROP_OPERATOR_ROLE, AIRDROP_PENALTY_OPERATOR_ROLE, PAUSING_CONTRACTS_ROLE, CONTRACT_USD0PP } from "src/constants.sol"; import { NullContract, NullMerkleRoot, InvalidProof, AmountTooBig, AmountIsZero, NotClaimableYet, NothingToClaim, SameValue, NullAddress, OutOfBounds, InvalidInputArraysLength, InvalidClaimingPeriodStartDate, AirdropVoided, NotAuthorized } from "src/errors.sol"; /// @title Airdrop Distribution contract /// @notice Manages the Airdrop Distribution /// @author Usual Tech team contract AirdropDistribution is Initializable, PausableUpgradeable, ReentrancyGuardUpgradeable, IAirdropDistribution { using Math for uint256; using CheckAccessControl for IRegistryAccess; /// @custom:storage-location erc7201:AirdropDistribution.storage.v0 struct AirdropDistributionStorageV0 { // The registry access contract IRegistryAccess registryAccess; // The registry contract IRegistryContract registryContract; // The airdrop tax collector contract IAirdropTaxCollector airdropTaxCollector; // The usual token contract IUsual usualToken; // The merkle root of the distribution bytes32 merkleRoot; // The claimed amount for each account mapping(address => uint256) claimed; // The penalty percentage for each account for each month mapping(address => mapping(uint256 => uint256)) penaltyPercentageByMonth; // Whether the ragequit has been used, voiding any airdrop mapping(address => bool) ragequit; } // keccak256(abi.encode(uint256(keccak256("AirdropDistribution.storage.v0")) - 1)) & ~bytes32(uint256(0xff)) // solhint-disable-next-line bytes32 public constant AirdropDistributionStorageV0Location = 0x8c5333b52aa1c4b5abeff2afd2c59c576cb9feb83f66f959574b22a3a8f8cf00; /// @notice Returns the storage struct of the contract. /// @return $ . function _airdropDistributionStorageV0() internal pure returns (AirdropDistributionStorageV0 storage $) { bytes32 position = AirdropDistributionStorageV0Location; // solhint-disable-next-line no-inline-assembly assembly { $.slot := position } } /*////////////////////////////////////////////////////////////// Events //////////////////////////////////////////////////////////////*/ /// @notice Emitted when the merkle root is set /// @param merkleRoot The merkle root set event MerkleRootSet(bytes32 indexed merkleRoot); /// @notice Emitted when the penalty percentages are set /// @param accounts The accounts set /// @param penaltyPercentages The penalty percentages set /// @param month The month set event PenaltyPercentagesSet( address[] indexed accounts, uint256[] indexed penaltyPercentages, uint256 indexed month ); /// @notice Emitted when a claim is made /// @param account The account that made the claim /// @param amount The amount claimed event Claimed(address indexed account, uint256 indexed amount); /// @notice Emitted when an account ragequits the airdrop /// @param account The account that ragequitted the airdrop event Ragequit(address indexed account); /*/////////////////////////////////////////////////////////////// Constructor //////////////////////////////////////////////////////////////*/ /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /*////////////////////////////////////////////////////////////// Initializer //////////////////////////////////////////////////////////////*/ /// @notice Initializes the contract with a registry contract. /// @param _registryContract Address of the registry contract for role management. function initialize(address _registryContract) public initializer { if (_registryContract == address(0)) { revert NullContract(); } __Pausable_init_unchained(); __ReentrancyGuard_init_unchained(); AirdropDistributionStorageV0 storage $ = _airdropDistributionStorageV0(); $.registryContract = IRegistryContract(_registryContract); $.registryAccess = IRegistryAccess($.registryContract.getContract(CONTRACT_REGISTRY_ACCESS)); $.usualToken = IUsual($.registryContract.getContract(CONTRACT_USUAL)); $.airdropTaxCollector = IAirdropTaxCollector($.registryContract.getContract(CONTRACT_AIRDROP_TAX_COLLECTOR)); // Check if the start time is within the correct range if (AIRDROP_INITIAL_START_TIME >= FIRST_AIRDROP_VESTING_CLAIMING_DATE) { revert InvalidClaimingPeriodStartDate(); } // Sanity check of vesting constants if ( !( END_OF_EARLY_UNLOCK_PERIOD < FIRST_AIRDROP_VESTING_CLAIMING_DATE && FIRST_AIRDROP_VESTING_CLAIMING_DATE < SECOND_AIRDROP_VESTING_CLAIMING_DATE && SECOND_AIRDROP_VESTING_CLAIMING_DATE < THIRD_AIRDROP_VESTING_CLAIMING_DATE && THIRD_AIRDROP_VESTING_CLAIMING_DATE < FOURTH_AIRDROP_VESTING_CLAIMING_DATE && FOURTH_AIRDROP_VESTING_CLAIMING_DATE < FIFTH_AIRDROP_VESTING_CLAIMING_DATE && FIFTH_AIRDROP_VESTING_CLAIMING_DATE < SIXTH_AIRDROP_VESTING_CLAIMING_DATE ) ) { revert OutOfBounds(); } } /*////////////////////////////////////////////////////////////// Internal //////////////////////////////////////////////////////////////*/ /// @notice Computes the penalty amount for the given account. /// @param $ The storage struct of the contract. /// @param totalAmount Total amount claimable by the user. /// @param account Address of the account. /// @param monthsPassed Number of months passed since the start of the vesting period. /// @return The penalty amount. function _computePenalty( AirdropDistributionStorageV0 storage $, uint256 totalAmount, address account, uint256 monthsPassed ) internal returns (uint256) { uint256 penaltyAmount = 0; uint256 oneSixthAmount = totalAmount.mulDiv(1, AIRDROP_VESTING_DURATION_IN_MONTHS, Math.Rounding.Ceil); for (uint256 i = 1; i <= monthsPassed; i++) { if ($.penaltyPercentageByMonth[account][i] == 0) { continue; } else if ($.penaltyPercentageByMonth[account][i] == BASIS_POINT_BASE) { penaltyAmount += oneSixthAmount; } else { uint256 monthlyPenalty = oneSixthAmount.mulDiv($.penaltyPercentageByMonth[account][i], BASIS_POINT_BASE); penaltyAmount += monthlyPenalty; } $.penaltyPercentageByMonth[account][i] = 0; } return penaltyAmount; } /// @notice Checks how much a user can claim. /// @param $ The storage struct of the contract. /// @param account Address of the account. /// @param totalAmount Total amount claimable by the user. /// @param isTop80 Whether the account is in the top 80% of the distribution (only used for vesting). /// @return The amount available to claim. /// @return The penalty amount. function _available( AirdropDistributionStorageV0 storage $, address account, uint256 totalAmount, bool isTop80 ) internal returns (uint256, uint256) { if (block.timestamp < AIRDROP_INITIAL_START_TIME) { revert NotClaimableYet(); } uint256 claimableAmount = totalAmount; uint256 monthsPassed = _calculateMonthsPassed(); uint256 totalClaimed = $.claimed[account]; uint256 penaltyAmount = 0; bool hasPaidTax = $.airdropTaxCollector.hasPaidTax(account); if (isTop80 && !hasPaidTax) { // slither-disable-next-line incorrect-equality if (monthsPassed == 0) { revert NotClaimableYet(); } claimableAmount = totalAmount.mulDiv(monthsPassed, AIRDROP_VESTING_DURATION_IN_MONTHS); } // Penalty is computed only if the account is in the top 80% if (isTop80) { penaltyAmount = _computePenalty( $, totalAmount, account, hasPaidTax ? monthsPassed + 1 : monthsPassed ); } // Subtract penalties from the claimable amount if (penaltyAmount > claimableAmount) { penaltyAmount = claimableAmount; } claimableAmount -= penaltyAmount; if (claimableAmount <= totalClaimed) { revert NothingToClaim(); } return (claimableAmount - totalClaimed, penaltyAmount); } function _calculateMonthsPassed() internal view returns (uint256) { uint256[6] memory airdropClaimingDates = [ FIRST_AIRDROP_VESTING_CLAIMING_DATE, SECOND_AIRDROP_VESTING_CLAIMING_DATE, THIRD_AIRDROP_VESTING_CLAIMING_DATE, FOURTH_AIRDROP_VESTING_CLAIMING_DATE, FIFTH_AIRDROP_VESTING_CLAIMING_DATE, SIXTH_AIRDROP_VESTING_CLAIMING_DATE ]; uint256 monthsPassed = 0; for (uint256 i = 0; i < airdropClaimingDates.length;) { if (block.timestamp < airdropClaimingDates[i]) { return monthsPassed; } monthsPassed++; unchecked { ++i; } } return monthsPassed; } /// @notice Verify the merkle proof for the given account. /// @param $ The storage struct of the contract. /// @param account Address of the account. /// @param isTop80 Whether the account is in the top 80% of the distribution. /// @param totalAmount Total amount claimable by the user. /// @param proof Merkle proof. /// @return True if the proof is valid, false otherwise. function _verifyMerkleProof( AirdropDistributionStorageV0 storage $, address account, bool isTop80, uint256 totalAmount, bytes32[] calldata proof ) internal view returns (bool) { bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(account, totalAmount, isTop80)))); return MerkleProof.verify(proof, $.merkleRoot, leaf); } /*////////////////////////////////////////////////////////////// External //////////////////////////////////////////////////////////////*/ // @inheritdoc IAirdropDistribution function claim(address account, bool isTop80, uint256 amount, bytes32[] calldata proof) external nonReentrant whenNotPaused { if (account == address(0)) { revert NullAddress(); } if (amount == 0) { revert AmountIsZero(); } AirdropDistributionStorageV0 storage $ = _airdropDistributionStorageV0(); if (!_verifyMerkleProof($, account, isTop80, amount, proof)) { revert InvalidProof(); } if ($.ragequit[account]) { revert AirdropVoided(); } (uint256 amountToClaim, uint256 penaltyAmount) = _available($, account, amount, isTop80); $.claimed[account] += amountToClaim + penaltyAmount; $.usualToken.mint(account, amountToClaim); emit Claimed(account, amountToClaim); } /*////////////////////////////////////////////////////////////// Restricted functions //////////////////////////////////////////////////////////////*/ /// @notice Sets the merkle root for the distribution module. /// @param _merkleRoot The merkle root. function setMerkleRoot(bytes32 _merkleRoot) external { if (_merkleRoot == bytes32(0)) { revert NullMerkleRoot(); } AirdropDistributionStorageV0 storage $ = _airdropDistributionStorageV0(); $.registryAccess.onlyMatchingRole(AIRDROP_OPERATOR_ROLE); $.merkleRoot = _merkleRoot; emit MerkleRootSet(_merkleRoot); } /// @notice Sets the penalty percentages for multiple accounts for a given month. /// @param penaltyPercentages Array of penalty percentages in basis points. /// @param accounts Array of addresses of the accounts. /// @param month The month of the vesting period. function setPenaltyPercentages( uint256[] memory penaltyPercentages, address[] memory accounts, uint256 month ) external { uint256 monthsPassed = _calculateMonthsPassed(); // Validate the month is within the 6-month vesting period if (month < monthsPassed || month > AIRDROP_VESTING_DURATION_IN_MONTHS) { revert OutOfBounds(); } // Validate the length of the arrays if (penaltyPercentages.length != accounts.length) { revert InvalidInputArraysLength(); } AirdropDistributionStorageV0 storage $ = _airdropDistributionStorageV0(); $.registryAccess.onlyMatchingRole(AIRDROP_PENALTY_OPERATOR_ROLE); for (uint256 i = 0; i < accounts.length; i++) { if (penaltyPercentages[i] > BASIS_POINT_BASE) { revert AmountTooBig(); } if (penaltyPercentages[i] == $.penaltyPercentageByMonth[accounts[i]][month]) { revert SameValue(); } $.penaltyPercentageByMonth[accounts[i]][month] = penaltyPercentages[i]; } emit PenaltyPercentagesSet(accounts, penaltyPercentages, month); } /// @notice Pauses the claim contract function /// @dev Can only be called by the PAUSING_CONTRACTS_ROLE. function pause() external { AirdropDistributionStorageV0 storage $ = _airdropDistributionStorageV0(); $.registryAccess.onlyMatchingRole(PAUSING_CONTRACTS_ROLE); _pause(); } /// @notice Unpauses the claim contract function /// @dev Can only be called by the admin. function unpause() external { AirdropDistributionStorageV0 storage $ = _airdropDistributionStorageV0(); $.registryAccess.onlyMatchingRole(DEFAULT_ADMIN_ROLE); _unpause(); } // @inheritdoc IAirdropDistribution function voidAnyOutstandingAirdrop(address account) external { AirdropDistributionStorageV0 storage $ = _airdropDistributionStorageV0(); // Verify that calling contract is the USD0PP contract if (msg.sender != $.registryContract.getContract(CONTRACT_USD0PP)) { revert NotAuthorized(); } if ($.ragequit[account]) { revert AirdropVoided(); } $.ragequit[account] = true; emit Ragequit(account); } /*////////////////////////////////////////////////////////////// Getters //////////////////////////////////////////////////////////////*/ /// @notice Returns the merkle root. /// @return The merkle root. function getMerkleRoot() external view returns (bytes32) { AirdropDistributionStorageV0 storage $ = _airdropDistributionStorageV0(); return $.merkleRoot; } /// @notice Returns the penalty percentage for the given account. /// @param account Address of the account. /// @param month The month of the vesting period. /// @return The penalty percentage in basis points for the given account and month. function getPenaltyPercentage(address account, uint256 month) external view returns (uint256) { AirdropDistributionStorageV0 storage $ = _airdropDistributionStorageV0(); return $.penaltyPercentageByMonth[account][month]; } /// @notice Returns the vesting duration of the distribution. /// @return The vesting duration. function getVestingDuration() external pure returns (uint256) { return SIXTH_AIRDROP_VESTING_CLAIMING_DATE - AIRDROP_INITIAL_START_TIME; } /// @notice Returns the claimed amount for the given account. /// @param account Address of the account. /// @return The claimed amount. function getClaimed(address account) external view returns (uint256) { AirdropDistributionStorageV0 storage $ = _airdropDistributionStorageV0(); return $.claimed[account]; } // @inheritdoc IAirdropDistribution function getRagequitStatus(address account) external view returns (bool) { AirdropDistributionStorageV0 storage $ = _airdropDistributionStorageV0(); return $.ragequit[account]; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Pausable struct PausableStorage { bool _paused; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300; function _getPausableStorage() private pure returns (PausableStorage storage $) { assembly { $.slot := PausableStorageLocation } } /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); /** * @dev The operation failed because the contract is paused. */ error EnforcedPause(); /** * @dev The operation failed because the contract is not paused. */ error ExpectedPause(); /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { PausableStorage storage $ = _getPausableStorage(); $._paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { PausableStorage storage $ = _getPausableStorage(); return $._paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert EnforcedPause(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert ExpectedPause(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { PausableStorage storage $ = _getPausableStorage(); $._paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { PausableStorage storage $ = _getPausableStorage(); $._paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard struct ReentrancyGuardStorage { uint256 _status; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { assembly { $.slot := ReentrancyGuardStorageLocation } } /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); $._status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // On the first call to nonReentrant, _status will be NOT_ENTERED if ($._status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail $._status = ENTERED; } function _nonReentrantAfter() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) $._status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); return $._status == ENTERED; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; import {IRegistryAccess} from "src/interfaces/registry/IRegistryAccess.sol"; import {NotAuthorized} from "src/errors.sol"; /// @title Check Access control library library CheckAccessControl { /// @dev Function to restrict to one access role. /// @param registryAccess The registry access contract. /// @param role The role being checked. function onlyMatchingRole(IRegistryAccess registryAccess, bytes32 role) internal view { if (!registryAccess.hasRole(role, msg.sender)) { revert NotAuthorized(); } } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; import {IAccessControlDefaultAdminRules} from "openzeppelin-contracts/access/extensions/IAccessControlDefaultAdminRules.sol"; // solhint-disable-next-line no-empty-blocks interface IRegistryAccess is IAccessControlDefaultAdminRules {}
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; interface IRegistryContract { function setContract(bytes32 name, address contractAddress) external; function getContract(bytes32 name) external view returns (address); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; interface IAirdropDistribution { /// @notice Claims the airdrop for the given account. /// @param account The account to claim for. /// @param isTop80 Whether the account is in the top 80% of the distribution. /// @param amount Total amount claimable by the user. /// @param proof Merkle proof. function claim(address account, bool isTop80, uint256 amount, bytes32[] calldata proof) external; /// @notice If a user early unlocks any USD0PP tokens via the temporaryOneToOneExitUnwrap function, /// @notice the USD0PP contract disables any claiming of outstanding tokens on the airdrop module /// @dev Can only be called by the CONTRACT_USD0PP role. /// @param addressToVoidAirdrop The address to disable the airdrop for. function voidAnyOutstandingAirdrop(address addressToVoidAirdrop) external; /// @notice Returns the status of ragequitting from airdrop for the given account. /// @param account Address of the account. /// @return The ragequit status. function getRagequitStatus(address account) external returns (bool); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; interface IAirdropTaxCollector { /// @notice Returns whether the claimer has paid tax in USD0PP. /// @param claimer The claimer to check. /// @return Whether the claimer has paid tax. function hasPaidTax(address claimer) external view returns (bool); /// @notice Pays the tax amount for the sender. /// @dev This function can only be called when the contract is not paused. /// @dev This function can only be called during the claiming period. function payTaxAmount() external; /// @notice Calculates the tax amount for the given account. /// @param account The account to calculate the tax amount for. /// @return The tax amount. function calculateClaimTaxAmount(address account) external view returns (uint256); /// @notice Gets start and end date of the claiming period. /// @return startDate The start date of the claiming period. /// @return endDate The end date of the claiming period. function getClaimingPeriod() external view returns (uint256 startDate, uint256 endDate); /// @notice Gets the maximum chargeable tax that is reduced over time. /// @return The maximum chargeable tax. function getMaxChargeableTax() external view returns (uint256); /// @notice Sets the maximum chargeable tax. /// @param tax The new maximum chargeable tax. /// @dev This function can only be called by an airdrop operator. function setMaxChargeableTax(uint256 tax) external; /// @notice Sets the prelaunch USD0pp balances for potential tax payment calculations of the users /// @param addressesToAllocateTo The addresses to allocate to /// @param prelaunchBalances The balances to allocate to function setUsd0ppPrelaunchBalances( address[] calldata addressesToAllocateTo, uint256[] calldata prelaunchBalances ) external; }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; import {IERC20Metadata} from "openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol"; interface IUsual is IERC20Metadata { /// @notice mint Usual token /// @dev Can only be called by USUAL_MINT role /// @param to address of the account who want to mint their token /// @param amount the amount of tokens to mint function mint(address to, uint256 amount) external; /// @notice burnFrom Usual token /// @dev Can only be called by USUAL_BURN role /// @param account address of the account who want to burn /// @param amount the amount of tokens to burn function burnFrom(address account, uint256 amount) external; /// @notice burn Usual token /// @dev Can only be called by USUAL_BURN role /// @param amount the amount of tokens to burn function burn(uint256 amount) external; /// @notice check if the account is blacklisted /// @param account address of the account to check /// @return bool function isBlacklisted(address account) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.20; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The tree and the proofs can be generated using our * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. * You will find a quickstart guide in the readme. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the Merkle tree could be reinterpreted as a leaf value. * OpenZeppelin's JavaScript library generates Merkle trees that are safe * against this attack out of the box. */ library MerkleProof { /** * @dev The multiproof provided is not valid. */ error MerkleProofInvalidMultiproof(); /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} */ function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. */ function multiProofVerify(bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false * respectively. * * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). */ function processMultiProof(bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves) internal pure returns (bytes32 merkleRoot) { // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the Merkle tree. uint256 leavesLen = leaves.length; uint256 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. if (leavesLen + proofLen != totalHashes + 1) { revert MerkleProofInvalidMultiproof(); } // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { if (proofPos != proofLen) { revert MerkleProofInvalidMultiproof(); } unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. */ function processMultiProofCalldata(bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves) internal pure returns (bytes32 merkleRoot) { // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the Merkle tree. uint256 leavesLen = leaves.length; uint256 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. if (leavesLen + proofLen != totalHashes + 1) { revert MerkleProofInvalidMultiproof(); } // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { if (proofPos != proofLen) { revert MerkleProofInvalidMultiproof(); } unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Sorts the pair (a, b) and hashes the result. */ function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } /** * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory. */ function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; /* Roles */ bytes32 constant DEFAULT_ADMIN_ROLE = 0x00; bytes32 constant PAUSING_CONTRACTS_ROLE = keccak256("PAUSING_CONTRACTS_ROLE"); bytes32 constant EARLY_BOND_UNLOCK_ROLE = keccak256("EARLY_BOND_UNLOCK_ROLE"); bytes32 constant BLACKLIST_ROLE = keccak256("BLACKLIST_ROLE"); bytes32 constant WHITELIST_ROLE = keccak256("WHITELIST_ROLE"); bytes32 constant WITHDRAW_FEE_UPDATER_ROLE = keccak256("WITHDRAW_FEE_UPDATER_ROLE"); bytes32 constant FEE_SWEEPER_ROLE = keccak256("FEE_SWEEPER_ROLE"); bytes32 constant BURN_RATIO_UPDATER_ROLE = keccak256("BURN_RATIO_UPDATER_ROLE"); bytes32 constant FLOOR_PRICE_UPDATER_ROLE = keccak256("FLOOR_PRICE_UPDATER_ROLE"); bytes32 constant DAO_COLLATERAL = keccak256("DAO_COLLATERAL_CONTRACT"); bytes32 constant USUALSP = keccak256("USUALSP_CONTRACT"); bytes32 constant USD0_MINT = keccak256("USD0_MINT"); bytes32 constant USD0_BURN = keccak256("USD0_BURN"); bytes32 constant USD0PP_MINT = keccak256("USD0PP_MINT"); bytes32 constant USD0PP_BURN = keccak256("USD0PP_BURN"); bytes32 constant USUALS_BURN = keccak256("USUALS_BURN"); bytes32 constant USUAL_MINT = keccak256("USUAL_MINT"); bytes32 constant USUAL_BURN = keccak256("USUAL_BURN"); bytes32 constant INTENT_MATCHING_ROLE = keccak256("INTENT_MATCHING_ROLE"); bytes32 constant NONCE_THRESHOLD_SETTER_ROLE = keccak256("NONCE_THRESHOLD_SETTER_ROLE"); bytes32 constant PEG_MAINTAINER_ROLE = keccak256("PEG_MAINTAINER_ROLE"); bytes32 constant PEG_MAINTAINER_UNLIMITED_ROLE = keccak256("PEG_MAINTAINER_UNLIMITED_ROLE"); bytes32 constant USD0PP_CAPPED_UNWRAP_ROLE = keccak256("USD0PP_CAPPED_UNWRAP_ROLE"); bytes32 constant UNWRAP_CAP_ALLOCATOR_ROLE = keccak256("UNWRAP_CAP_ALLOCATOR_ROLE"); bytes32 constant SWAPPER_ENGINE = keccak256("SWAPPER_ENGINE"); bytes32 constant INTENT_TYPE_HASH = keccak256( "SwapIntent(address recipient,address rwaToken,uint256 amountInTokenDecimals,uint256 nonce,uint256 deadline)" ); bytes32 constant DISTRIBUTION_ALLOCATOR_ROLE = keccak256("DISTRIBUTION_ALLOCATOR_ROLE"); bytes32 constant DISTRIBUTION_OPERATOR_ROLE = keccak256("DISTRIBUTION_OPERATOR_ROLE"); bytes32 constant DISTRIBUTION_CHALLENGER_ROLE = keccak256("DISTRIBUTION_CHALLENGER_ROLE"); bytes32 constant USD0PP_USUAL_DISTRIBUTION_ROLE = keccak256("USD0PP_USUAL_DISTRIBUTION_ROLE"); bytes32 constant USD0PP_DURATION_COST_FACTOR_ROLE = keccak256("USD0PP_DURATION_COST_FACTOR_ROLE"); bytes32 constant USD0PP_TREASURY_ALLOCATION_RATE_ROLE = keccak256("USD0PP_TREASURY_ALLOCATION_RATE_ROLE"); bytes32 constant USD0PP_TARGET_REDEMPTION_RATE_ROLE = keccak256("USD0PP_TARGET_REDEMPTION_RATE_ROLE"); /* Airdrop Roles */ bytes32 constant AIRDROP_OPERATOR_ROLE = keccak256("AIRDROP_OPERATOR_ROLE"); bytes32 constant AIRDROP_PENALTY_OPERATOR_ROLE = keccak256("AIRDROP_PENALTY_OPERATOR_ROLE"); bytes32 constant USUALSP_OPERATOR_ROLE = keccak256("USUALSP_OPERATOR_ROLE"); /* Contracts */ bytes32 constant CONTRACT_REGISTRY_ACCESS = keccak256("CONTRACT_REGISTRY_ACCESS"); bytes32 constant CONTRACT_DAO_COLLATERAL = keccak256("CONTRACT_DAO_COLLATERAL"); bytes32 constant CONTRACT_USD0PP = keccak256("CONTRACT_USD0PP"); bytes32 constant CONTRACT_USUALS = keccak256("CONTRACT_USUALS"); bytes32 constant CONTRACT_USUALSP = keccak256("CONTRACT_USUALSP"); bytes32 constant CONTRACT_TOKEN_MAPPING = keccak256("CONTRACT_TOKEN_MAPPING"); bytes32 constant CONTRACT_ORACLE = keccak256("CONTRACT_ORACLE"); bytes32 constant CONTRACT_ORACLE_USUAL = keccak256("CONTRACT_ORACLE_USUAL"); bytes32 constant CONTRACT_DATA_PUBLISHER = keccak256("CONTRACT_DATA_PUBLISHER"); bytes32 constant CONTRACT_TREASURY = keccak256("CONTRACT_TREASURY"); bytes32 constant CONTRACT_YIELD_TREASURY = keccak256("CONTRACT_YIELD_TREASURY"); bytes32 constant CONTRACT_SWAPPER_ENGINE = keccak256("CONTRACT_SWAPPER_ENGINE"); bytes32 constant CONTRACT_AIRDROP_DISTRIBUTION = keccak256("CONTRACT_AIRDROP_DISTRIBUTION"); bytes32 constant CONTRACT_AIRDROP_TAX_COLLECTOR = keccak256("CONTRACT_AIRDROP_TAX_COLLECTOR"); bytes32 constant CONTRACT_DISTRIBUTION_MODULE = keccak256("CONTRACT_DISTRIBUTION_MODULE"); /* Registry */ bytes32 constant CONTRACT_REGISTRY = keccak256("CONTRACT_REGISTRY"); // Not set on production /* Contract tokens */ bytes32 constant CONTRACT_USD0 = keccak256("CONTRACT_USD0"); bytes32 constant CONTRACT_USUAL = keccak256("CONTRACT_USUAL"); bytes32 constant CONTRACT_USDC = keccak256("CONTRACT_USDC"); bytes32 constant CONTRACT_USUALX = keccak256("CONTRACT_USUALX"); /* Token names and symbols */ string constant USUALSSymbol = "USUAL*"; string constant USUALSName = "USUAL Star"; string constant USUALSymbol = "USUAL"; string constant USUALName = "USUAL"; string constant USUALXSymbol = "USUALX"; string constant USUALXName = "USUALX"; /* Constants */ uint256 constant INITIAL_ACCUMULATED_FEES = 0; // For now, we don't have any fees accumulated. This constant can be used to initialize the contract with the correct amount of fees. uint256 constant INITIAL_SHARES_MINTING = 10_000e18; // For now, we mint "dead" shares has we started distribution early. This constant will be used to initialize the contract with the correct amount. uint256 constant SCALAR_ONE = 1e18; uint256 constant BPS_SCALAR = 10_000; // 10000 basis points = 100% uint256 constant DISTRIBUTION_FREQUENCY_SCALAR = 1 days; uint256 constant SCALAR_TEN_KWEI = 10_000; uint256 constant MAX_REDEEM_FEE = 2500; uint256 constant MINIMUM_USDC_PROVIDED = 100e6; //minimum of 100 USDC deposit; // we take 12sec as the average block time // 1 year = 3600sec * 24 hours * 365 days * 4 years = 126_144_000 + 1 day // adding a leap day uint256 constant BOND_DURATION_FOUR_YEAR = 126_230_400; //including a leap day; uint256 constant USUAL_DISTRIBUTION_CHALLENGE_PERIOD = 1 weeks; uint256 constant BASIS_POINT_BASE = 10_000; uint256 constant INITIAL_BURN_RATIO_BPS = 3334; uint256 constant VESTING_DURATION_THREE_YEARS = 94_608_000; // 3 years uint256 constant USUALSP_VESTING_STARTING_DATE = 1_732_530_600; // Mon Nov 25 2024 10:30:00 GMT+0000 uint256 constant STARTDATE_USUAL_CLAIMING_USUALSP = 1_764_066_600; // Tue Nov 25 2025 10:30:00 GMT+0000 uint256 constant STARTDATE_USUAL_CLAIMING_DISTRIBUTION_MODULE = 1_734_516_000; // Dec 18 2024 10:00:00 GMT+0000 uint256 constant AIRDROP_INITIAL_START_TIME = 1_734_516_000; // Dec 18 2024 10:00:00 GMT+0000 uint256 constant AIRDROP_VESTING_DURATION_IN_MONTHS = 6; uint256 constant ONE_YEAR = 31_536_000; // 365 days uint256 constant SIX_MONTHS = 15_768_000; uint256 constant ONE_MONTH = 2_628_000; // ONE_YEAR / 12 = 30,4 days uint64 constant ONE_WEEK = 604_800; uint256 constant NUMBER_OF_MONTHS_IN_THREE_YEARS = 36; uint256 constant END_OF_EARLY_UNLOCK_PERIOD = 1_735_686_000; // 31st Dec 2024 23:00:00 GMT+0000 uint256 constant FIRST_AIRDROP_VESTING_CLAIMING_DATE = 1_737_194_400; // 18th Jan 2025 10:00:00 GMT+0000 uint256 constant SECOND_AIRDROP_VESTING_CLAIMING_DATE = 1_739_872_800; // 18th Feb 2025 10:00:00 GMT+0000 uint256 constant THIRD_AIRDROP_VESTING_CLAIMING_DATE = 1_742_292_000; // 18th Mar 2025 10:00:00 GMT+0000 uint256 constant FOURTH_AIRDROP_VESTING_CLAIMING_DATE = 1_744_970_400; // 18th Apr 2025 10:00:00 GMT+0000 uint256 constant FIFTH_AIRDROP_VESTING_CLAIMING_DATE = 1_747_562_400; // 18th May 2025 10:00:00 GMT+0000 uint256 constant SIXTH_AIRDROP_VESTING_CLAIMING_DATE = 1_750_240_800; // 18th Jun 2025 10:00:00 GMT+0000 uint256 constant INITIAL_FLOOR_PRICE = 999_500_000_000_000_000; // 1 USD0++ = 0.9995 USD0 /* UsualX initial withdraw fee */ uint256 constant USUALX_WITHDRAW_FEE = 1000; // in BPS 10% /* Usual Distribution Bucket Distribution Shares */ uint256 constant LBT_DISTRIBUTION_SHARE = 3552; uint256 constant LYT_DISTRIBUTION_SHARE = 1026; // USD0/USD0++ AND USD0/USDC summed up uint256 constant IYT_DISTRIBUTION_SHARE = 0; uint256 constant BRIBE_DISTRIBUTION_SHARE = 346; uint256 constant ECO_DISTRIBUTION_SHARE = 0; uint256 constant DAO_DISTRIBUTION_SHARE = 1620; uint256 constant MARKET_MAKERS_DISTRIBUTION_SHARE = 0; uint256 constant USUALX_DISTRIBUTION_SHARE = 1728; uint256 constant USUALSTAR_DISTRIBUTION_SHARE = 1728; uint256 constant INITIAL_BASE_GAMMA = 7894; // 78.94 uint256 constant ONE_USDC = 1e6; uint256 constant MAX_25_PERCENT_WITHDRAW_FEE = 2500; // 25% fee uint256 constant YIELD_PRECISION = 1 days; uint256 constant USUALS_TOTAL_SUPPLY = 360_000_000e18; uint256 constant PRICE_TIMEOUT = 7 days; address constant SUSDE_CHAINLINK_PRICE_ORACLE = 0xFF3BC18cCBd5999CE63E788A1c250a88626aD099; uint256 constant CHAINLINK_PRICE_SCALAR = 1e8; /* Usual burn initial parameters */ uint256 constant INITIAL_USUAL_BURN_TREASURY_ALLOCATION_RATE = 6666; // 66.66% in basis points uint256 constant INITIAL_USUAL_BURN_DURATION_COST_FACTOR = 180; // 180 days uint256 constant INITIAL_USUAL_BURN_TARGET_REDEMPTION_RATE = 30; // 0.3% in basis points uint256 constant INITIAL_USUAL_BURN_USUAL_DISTRIBUTION_PER_USD0PP = 3e15; // 0.003 Usual per USD0PP uint256 constant USD0PP_NET_OUTFLOWS_ROLLING_WINDOW_DAYS = 7; // 7 days /* Token Addresses */ address constant USYC = 0x136471a34f6ef19fE571EFFC1CA711fdb8E49f2b; address constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; /* * The maximum relative price difference between two oracle responses allowed in order for the PriceFeed * to return to using the Oracle oracle. 18-digit precision. */ uint256 constant INITIAL_MAX_DEPEG_THRESHOLD = 100; /* Maximum number of RWA tokens that can be associated with USD0 */ uint256 constant MAX_RWA_COUNT = 10; /* Curvepool Addresses */ address constant CURVE_POOL_USD0_USD0PP = 0x1d08E7adC263CfC70b1BaBe6dC5Bb339c16Eec52; int128 constant CURVE_POOL_USD0_USD0PP_INTEGER_FOR_USD0 = 0; int128 constant CURVE_POOL_USD0_USD0PP_INTEGER_FOR_USD0PP = 1; /* Airdrop */ uint256 constant AIRDROP_CLAIMING_PERIOD_LENGTH = 182 days; /* Distribution */ uint256 constant RATE0 = 400; // 4.03% in basis points /* Hexagate */ address constant HEXAGATE_PAUSER = 0x114644925eD9A6Ab20bF85f36F1a458DF181b57B; /* Mainnet Usual Deployment */ address constant USUAL_MULTISIG_MAINNET = 0x6e9d65eC80D69b1f508560Bc7aeA5003db1f7FB7; address constant USUAL_PROXY_ADMIN_MAINNET = 0xaaDa24358620d4638a2eE8788244c6F4b197Ca16; address constant REGISTRY_CONTRACT_MAINNET = 0x0594cb5ca47eFE1Ff25C7B8B43E221683B4Db34c; address constant USUALX_REDISTRIBUTION_CONTRACT = 0x351B2AFa5C8e5Ff0644Fef2bEE5cA2B8Df56715A;
// SPDX-License-Identifier: Apache-2.0 pragma solidity 0.8.20; error AlreadyClaimed(); error NothingToClaim(); error AlreadyWhitelisted(); error AmountTooBig(); error AmountTooLow(); error AmountIsZero(); error Blacklisted(); error ExpiredSignature(uint256 deadline); error SameValue(); error Invalid(); error InvalidInput(); error InvalidToken(); error InvalidName(); error InvalidSigner(address owner); error InvalidDeadline(uint256 approvalDeadline, uint256 intentDeadline); error NoOrdersIdsProvided(); error InvalidSymbol(); error InvalidInputArraysLength(); error NotAuthorized(); error NotClaimableYet(); error NullAddress(); error NullContract(); error OracleNotWorkingNotCurrent(); error OracleNotInitialized(); error OutOfBounds(); error InvalidTimeout(); error RedeemMustNotBePaused(); error RedeemMustBePaused(); error SwapMustNotBePaused(); error SwapMustBePaused(); error StablecoinDepeg(); error DepegThresholdTooHigh(); error BondNotStarted(); error BondFinished(); error BondNotFinished(); error CliffBiggerThanDuration(); error BeginInPast(); error EndTimeBeforeStartTime(); error StartTimeInPast(); error AlreadyStarted(); error CBRIsTooHigh(); error CBRIsNull(); error RedeemFeeTooBig(); error TooManyRWA(); error InsufficientUSD0Balance(); error InsufficientUsualSLiquidAllocation(); error CannotReduceAllocation(); error OrderNotActive(); error NotRequester(); error ApprovalFailed(); error AmountExceedBacking(); error InvalidOrderAmount(address account, uint256 amount); error PARNotRequired(); error PARNotSuccessful(); error PARUSD0InputExceedsBalance(); error NullMerkleRoot(); error InvalidProof(); error PercentagesSumNotEqualTo100Percent(); error CannotDistributeUsualMoreThanOnceADay(); error NoOffChainDistributionToApprove(); error NoTokensToClaim(); error InvalidOrderId(uint80 roundId); error NotOwner(); error InvalidClaimingPeriodStartDate(); error InvalidMaxChargeableTax(); error NotInClaimingPeriod(); error ClaimerHasPaidTax(); error ZeroYieldAmount(); error StartTimeNotInFuture(); error StartTimeBeforePeriodFinish(); error CurrentTimeBeforePeriodFinish(); error EndTimeNotAfterStartTime(); error InsufficientAssetsForYield(); error InsufficientAssets(); error InsufficientSupply(); error NotPermittedToEarlyUnlock(); error OutsideEarlyUnlockTimeframe(); error AirdropVoided(); error FloorPriceTooHigh(); error AmountMustBeGreaterThanZero(); error InsufficientUsd0ppBalance(); error UsualAmountTooLow(); error UsualAmountIsZero(); error FloorPriceNotSet(); error UnwrapCapNotSet(); error AmountTooBigForCap(); error StalePrice(); error InvalidPrice();
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlDefaultAdminRules.sol) pragma solidity ^0.8.20; import {IAccessControl} from "../IAccessControl.sol"; /** * @dev External interface of AccessControlDefaultAdminRules declared to support ERC165 detection. */ interface IAccessControlDefaultAdminRules is IAccessControl { /** * @dev The new default admin is not a valid default admin. */ error AccessControlInvalidDefaultAdmin(address defaultAdmin); /** * @dev At least one of the following rules was violated: * * - The `DEFAULT_ADMIN_ROLE` must only be managed by itself. * - The `DEFAULT_ADMIN_ROLE` must only be held by one account at the time. * - Any `DEFAULT_ADMIN_ROLE` transfer must be in two delayed steps. */ error AccessControlEnforcedDefaultAdminRules(); /** * @dev The delay for transferring the default admin delay is enforced and * the operation must wait until `schedule`. * * NOTE: `schedule` can be 0 indicating there's no transfer scheduled. */ error AccessControlEnforcedDefaultAdminDelay(uint48 schedule); /** * @dev Emitted when a {defaultAdmin} transfer is started, setting `newAdmin` as the next * address to become the {defaultAdmin} by calling {acceptDefaultAdminTransfer} only after `acceptSchedule` * passes. */ event DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule); /** * @dev Emitted when a {pendingDefaultAdmin} is reset if it was never accepted, regardless of its schedule. */ event DefaultAdminTransferCanceled(); /** * @dev Emitted when a {defaultAdminDelay} change is started, setting `newDelay` as the next * delay to be applied between default admin transfer after `effectSchedule` has passed. */ event DefaultAdminDelayChangeScheduled(uint48 newDelay, uint48 effectSchedule); /** * @dev Emitted when a {pendingDefaultAdminDelay} is reset if its schedule didn't pass. */ event DefaultAdminDelayChangeCanceled(); /** * @dev Returns the address of the current `DEFAULT_ADMIN_ROLE` holder. */ function defaultAdmin() external view returns (address); /** * @dev Returns a tuple of a `newAdmin` and an accept schedule. * * After the `schedule` passes, the `newAdmin` will be able to accept the {defaultAdmin} role * by calling {acceptDefaultAdminTransfer}, completing the role transfer. * * A zero value only in `acceptSchedule` indicates no pending admin transfer. * * NOTE: A zero address `newAdmin` means that {defaultAdmin} is being renounced. */ function pendingDefaultAdmin() external view returns (address newAdmin, uint48 acceptSchedule); /** * @dev Returns the delay required to schedule the acceptance of a {defaultAdmin} transfer started. * * This delay will be added to the current timestamp when calling {beginDefaultAdminTransfer} to set * the acceptance schedule. * * NOTE: If a delay change has been scheduled, it will take effect as soon as the schedule passes, making this * function returns the new delay. See {changeDefaultAdminDelay}. */ function defaultAdminDelay() external view returns (uint48); /** * @dev Returns a tuple of `newDelay` and an effect schedule. * * After the `schedule` passes, the `newDelay` will get into effect immediately for every * new {defaultAdmin} transfer started with {beginDefaultAdminTransfer}. * * A zero value only in `effectSchedule` indicates no pending delay change. * * NOTE: A zero value only for `newDelay` means that the next {defaultAdminDelay} * will be zero after the effect schedule. */ function pendingDefaultAdminDelay() external view returns (uint48 newDelay, uint48 effectSchedule); /** * @dev Starts a {defaultAdmin} transfer by setting a {pendingDefaultAdmin} scheduled for acceptance * after the current timestamp plus a {defaultAdminDelay}. * * Requirements: * * - Only can be called by the current {defaultAdmin}. * * Emits a DefaultAdminRoleChangeStarted event. */ function beginDefaultAdminTransfer(address newAdmin) external; /** * @dev Cancels a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}. * * A {pendingDefaultAdmin} not yet accepted can also be cancelled with this function. * * Requirements: * * - Only can be called by the current {defaultAdmin}. * * May emit a DefaultAdminTransferCanceled event. */ function cancelDefaultAdminTransfer() external; /** * @dev Completes a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}. * * After calling the function: * * - `DEFAULT_ADMIN_ROLE` should be granted to the caller. * - `DEFAULT_ADMIN_ROLE` should be revoked from the previous holder. * - {pendingDefaultAdmin} should be reset to zero values. * * Requirements: * * - Only can be called by the {pendingDefaultAdmin}'s `newAdmin`. * - The {pendingDefaultAdmin}'s `acceptSchedule` should've passed. */ function acceptDefaultAdminTransfer() external; /** * @dev Initiates a {defaultAdminDelay} update by setting a {pendingDefaultAdminDelay} scheduled for getting * into effect after the current timestamp plus a {defaultAdminDelay}. * * This function guarantees that any call to {beginDefaultAdminTransfer} done between the timestamp this * method is called and the {pendingDefaultAdminDelay} effect schedule will use the current {defaultAdminDelay} * set before calling. * * The {pendingDefaultAdminDelay}'s effect schedule is defined in a way that waiting until the schedule and then * calling {beginDefaultAdminTransfer} with the new delay will take at least the same as another {defaultAdmin} * complete transfer (including acceptance). * * The schedule is designed for two scenarios: * * - When the delay is changed for a larger one the schedule is `block.timestamp + newDelay` capped by * {defaultAdminDelayIncreaseWait}. * - When the delay is changed for a shorter one, the schedule is `block.timestamp + (current delay - new delay)`. * * A {pendingDefaultAdminDelay} that never got into effect will be canceled in favor of a new scheduled change. * * Requirements: * * - Only can be called by the current {defaultAdmin}. * * Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event. */ function changeDefaultAdminDelay(uint48 newDelay) external; /** * @dev Cancels a scheduled {defaultAdminDelay} change. * * Requirements: * * - Only can be called by the current {defaultAdmin}. * * May emit a DefaultAdminDelayChangeCanceled event. */ function rollbackDefaultAdminDelay() external; /** * @dev Maximum time in seconds for an increase to {defaultAdminDelay} (that is scheduled using {changeDefaultAdminDelay}) * to take effect. Default to 5 days. * * When the {defaultAdminDelay} is scheduled to be increased, it goes into effect after the new delay has passed with * the purpose of giving enough time for reverting any accidental change (i.e. using milliseconds instead of seconds) * that may lock the contract. However, to avoid excessive schedules, the wait is capped by this function and it can * be overrode for a custom {defaultAdminDelay} increase scheduling. * * IMPORTANT: Make sure to add a reasonable amount of time while overriding this value, otherwise, * there's a risk of setting a high new delay that goes into effect almost immediately without the * possibility of human intervention in the case of an input error (eg. set milliseconds instead of seconds). */ function defaultAdminDelayIncreaseWait() external view returns (uint48); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "utils/=lib/utils/", "@openzeppelin/=lib/openzeppelin-contracts/", "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/", "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/", "src/=src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "shanghai", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AirdropVoided","type":"error"},{"inputs":[],"name":"AmountIsZero","type":"error"},{"inputs":[],"name":"AmountTooBig","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"InvalidClaimingPeriodStartDate","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidInputArraysLength","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotClaimableYet","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NothingToClaim","type":"error"},{"inputs":[],"name":"NullAddress","type":"error"},{"inputs":[],"name":"NullContract","type":"error"},{"inputs":[],"name":"NullMerkleRoot","type":"error"},{"inputs":[],"name":"OutOfBounds","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"SameValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"MerkleRootSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address[]","name":"accounts","type":"address[]"},{"indexed":true,"internalType":"uint256[]","name":"penaltyPercentages","type":"uint256[]"},{"indexed":true,"internalType":"uint256","name":"month","type":"uint256"}],"name":"PenaltyPercentagesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"Ragequit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"AirdropDistributionStorageV0Location","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"isTop80","type":"bool"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"getPenaltyPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getRagequitStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVestingDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_registryContract","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"penaltyPercentages","type":"uint256[]"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256","name":"month","type":"uint256"}],"name":"setPenaltyPercentages","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"voidAnyOutstandingAirdrop","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561000f575f80fd5b5061001861001d565b6100cf565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161561006d5760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146100cc5780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b611928806100dc5f395ff3fe608060405234801561000f575f80fd5b50600436106100e5575f3560e01c80635c975abb11610088578063c4d66de811610063578063c4d66de8146101fb578063d19ec90a1461020e578063eb46260e14610221578063fbed72fa14610268575f80fd5b80635c975abb146101c95780637cb64759146101e05780638456cb59146101f3575f80fd5b806338c30fb4116100c357806338c30fb41461012c5780633f4ba83a14610186578063495906571461018e5780635c52a56f146101b5575f80fd5b806321b1d7ad146100e95780632a9a6f9c146100fe5780632fccfbd214610111575b5f80fd5b6100fc6100f73660046114c3565b61027b565b005b6100fc61010c3660046114eb565b6103d1565b6101196105b2565b6040519081526020015b60405180910390f35b61017661013a3660046114c3565b6001600160a01b03165f9081527f8c5333b52aa1c4b5abeff2afd2c59c576cb9feb83f66f959574b22a3a8f8cf07602052604090205460ff1690565b6040519015158152602001610123565b6100fc6105ca565b7f8c5333b52aa1c4b5abeff2afd2c59c576cb9feb83f66f959574b22a3a8f8cf0454610119565b6101195f805160206118b383398151915281565b5f805160206118d38339815191525460ff16610176565b6100fc6101ee366004611585565b6105f8565b6100fc61068e565b6100fc6102093660046114c3565b6106d9565b61011961021c36600461159c565b610a24565b61011961022f3660046114c3565b6001600160a01b03165f9081527f8c5333b52aa1c4b5abeff2afd2c59c576cb9feb83f66f959574b22a3a8f8cf05602052604090205490565b6100fc61027636600461169f565b610a6d565b5f5f805160206118b38339815191526001810154604051631c2d8fb360e31b81527f2efffbdded4fb417a0f132bcfde583d2d04ac8103881725f3da21929432cf4d260048201529192506001600160a01b03169063e16c7d9890602401602060405180830381865afa1580156102f3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610317919061175a565b6001600160a01b0316336001600160a01b0316146103485760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0382165f90815260078201602052604090205460ff16156103835760405163d9eac9d960e01b815260040160405180910390fd5b6001600160a01b0382165f818152600783016020526040808220805460ff19166001179055517faca49f660bc1fd1b72001822dbb3912d5b785534ec802132a158e5b5de6197df9190a25050565b6103d9610cb0565b6103e1610cfa565b6001600160a01b0385166104085760405163e99d5ac560e01b815260040160405180910390fd5b825f03610428576040516310eb483f60e21b815260040160405180910390fd5b5f805160206118b3833981519152610444818787878787610d2c565b610461576040516309bde33960e01b815260040160405180910390fd5b6001600160a01b0386165f90815260078201602052604090205460ff161561049c5760405163d9eac9d960e01b815260040160405180910390fd5b5f806104aa8389888a610dd5565b90925090506104b98183611789565b6001600160a01b0389165f908152600585016020526040812080549091906104e2908490611789565b909155505060038301546040516340c10f1960e01b81526001600160a01b038a8116600483015260248201859052909116906340c10f19906044015f604051808303815f87803b158015610534575f80fd5b505af1158015610546573d5f803e3d5ffd5b50506040518492506001600160a01b038b1691507fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a905f90a35050506105ab60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050505050565b5f6105c56367629d206368528e2061179c565b905090565b5f805160206118b383398151915280546105ed906001600160a01b03165f610f71565b6105f5610fff565b50565b80610616576040516360a2b2e360e01b815260040160405180910390fd5b5f805160206118b38339815191528054610659906001600160a01b03167f228c42276f07752f6ef75920ba824d051df2b02ccab8e6b31f62bfaa658849d1610f71565b6004810182905560405182907f42cbc405e4dbf1b691e85b9a34b08ecfcf7a9ad9078bf4d645ccfa1fac11c10b905f90a25050565b5f805160206118b383398151915280546106d1906001600160a01b03167fe40ef4c9f0881870a532466eceeb9426f92f3b4563aab91fc873619411dc7014610f71565b6105f561105e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff165f8115801561071e5750825b90505f8267ffffffffffffffff16600114801561073a5750303b155b905081158015610748575080155b156107665760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561079057845460ff60401b1916600160401b1785555b6001600160a01b0386166107b7576040516307988a3f60e21b815260040160405180910390fd5b6107bf6110a6565b6107c76110c6565b5f5f805160206118b38339815191526001810180546001600160a01b0319166001600160a01b038a16908117909155604051631c2d8fb360e31b81527f5a92fc7720b8c2c63ba7a9aec6e2269feb0e8c23b216e4162abc2b6ed5e5a22b60048201529192509063e16c7d9890602401602060405180830381865afa158015610851573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610875919061175a565b81546001600160a01b0319166001600160a01b039182161782556001820154604051631c2d8fb360e31b81527fdbbc50039ed3ca50ec88fa75d6fe32dae25b22535afc1cd51cf4090d5ebc4d28600482015291169063e16c7d9890602401602060405180830381865afa1580156108ee573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610912919061175a565b6003820180546001600160a01b0319166001600160a01b039283161790556001820154604051631c2d8fb360e31b81527fc499adfcee6e085aaabecb4b8bbeb555bf87ab4b8b925c23c63822e6c935c4b0600482015291169063e16c7d9890602401602060405180830381865afa15801561098f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109b3919061175a565b6002820180546001600160a01b0319166001600160a01b0392909216919091179055508315610a1c57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b6001600160a01b0382165f9081527f8c5333b52aa1c4b5abeff2afd2c59c576cb9feb83f66f959574b22a3a8f8cf06602090815260408083208484529091529020545b92915050565b5f610a766110ce565b905080821080610a865750600682115b15610aa457604051632d0483c560e21b815260040160405180910390fd5b8251845114610ac6576040516308e8ba6f60e31b815260040160405180910390fd5b5f805160206118b38339815191528054610b09906001600160a01b03167f34e9d16462882c04e6106faa49ee9c90d25f46454ebf4084636951c74431b2a9610f71565b5f5b8451811015610c5457612710868281518110610b2957610b296117af565b60200260200101511115610b5057604051636b2f218360e01b815260040160405180910390fd5b816006015f868381518110610b6757610b676117af565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f8581526020019081526020015f2054868281518110610bb057610bb06117af565b602002602001015103610bd65760405163c23f6ccb60e01b815260040160405180910390fd5b858181518110610be857610be86117af565b6020026020010151826006015f878481518110610c0757610c076117af565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f8681526020019081526020015f20819055508080610c4c906117c3565b915050610b0b565b508285604051610c6491906117db565b604051809103902085604051610c7a9190611810565b604051908190038120907fc354b3c0578f84e812883d429ee41b8d75dfeff50ea66fa21da3b21b63aece0f905f90a45050505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901610cf457604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b5f805160206118d38339815191525460ff1615610d2a5760405163d93c066560e01b815260040160405180910390fd5b565b604080516001600160a01b038716602082015290810184905284151560608201525f90819060800160408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052805190602001209050610dc98484808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050505060048a015483611164565b98975050505050505050565b5f806367629d20421015610dfc57604051636c09fbc960e11b815260040160405180910390fd5b835f610e066110ce565b6001600160a01b038881165f81815260058c0160205260408082205460028e01549151632feaee9560e01b8152600481019490945294955090928392911690632feaee9590602401602060405180830381865afa158015610e69573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8d9190611842565b9050878015610e9a575080155b15610ece57835f03610ebf57604051636c09fbc960e11b815260040160405180910390fd5b610ecb8985600661117b565b94505b8715610ef857610ef58b8a8c84610ee5578761123a565b610ef0886001611789565b61123a565b91505b84821115610f04578491505b610f0e828661179c565b9450828511610f30576040516312d37ee560e31b815260040160405180910390fd5b610f3a838661179c565b9b919a509098505050505050505050565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b604051632474521560e21b8152600481018290523360248201526001600160a01b038316906391d1485490604401602060405180830381865afa158015610fba573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fde9190611842565b610ffb5760405163ea8e4eb560e01b815260040160405180910390fd5b5050565b611007611347565b5f805160206118d3833981519152805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b611066610cfa565b5f805160206118d3833981519152805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833611040565b6110ae611376565b5f805160206118d3833981519152805460ff19169055565b610f4b611376565b5f806040518060c0016040528063678b7ba081526020016367b45a2081526020016367d94420815260200163680222a08152602001636829afa081526020016368528e2081525090505f805b600681101561115d57828160068110611135576111356117af565b6020020151421015611148575092915050565b81611152816117c3565b92505060010161111a565b5092915050565b5f8261117085846113bf565b1490505b9392505050565b5f838302815f1985870982811083820303915050805f036111af578382816111a5576111a561185d565b0492505050611174565b8084116111cf5760405163227bc15360e01b815260040160405180910390fd5b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b5f808061124b86600160068161140b565b905060015b84811161133b576001600160a01b0386165f908152600689016020908152604080832084845290915290205415611329576001600160a01b0386165f908152600689016020908152604080832084845290915290205461270f19016112c0576112b98284611789565b9250611303565b6001600160a01b0386165f90815260068901602090815260408083208484529091528120546112f390849061271061117b565b90506112ff8185611789565b9350505b6001600160a01b0386165f90815260068901602090815260408083208484529091528120555b80611333816117c3565b915050611250565b50909695505050505050565b5f805160206118d38339815191525460ff16610d2a57604051638dfc202b60e01b815260040160405180910390fd5b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610d2a57604051631afcd79f60e31b815260040160405180910390fd5b5f81815b8451811015611403576113ef828683815181106113e2576113e26117af565b602002602001015161145a565b9150806113fb816117c3565b9150506113c3565b509392505050565b5f8061141886868661117b565b905061142383611483565b801561143e57505f84806114395761143961185d565b868809115b156114515761144e600182611789565b90505b95945050505050565b5f818310611474575f828152602084905260409020611174565b505f9182526020526040902090565b5f600282600381111561149857611498611871565b6114a29190611885565b60ff166001149050919050565b6001600160a01b03811681146105f5575f80fd5b5f602082840312156114d3575f80fd5b8135611174816114af565b80151581146105f5575f80fd5b5f805f805f608086880312156114ff575f80fd5b853561150a816114af565b9450602086013561151a816114de565b935060408601359250606086013567ffffffffffffffff8082111561153d575f80fd5b818801915088601f830112611550575f80fd5b81358181111561155e575f80fd5b8960208260051b8501011115611572575f80fd5b9699959850939650602001949392505050565b5f60208284031215611595575f80fd5b5035919050565b5f80604083850312156115ad575f80fd5b82356115b8816114af565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611603576116036115c6565b604052919050565b5f67ffffffffffffffff821115611624576116246115c6565b5060051b60200190565b5f82601f83011261163d575f80fd5b8135602061165261164d8361160b565b6115da565b82815260059290921b84018101918181019086841115611670575f80fd5b8286015b84811015611694578035611687816114af565b8352918301918301611674565b509695505050505050565b5f805f606084860312156116b1575f80fd5b833567ffffffffffffffff808211156116c8575f80fd5b818601915086601f8301126116db575f80fd5b813560206116eb61164d8361160b565b82815260059290921b8401810191818101908a841115611709575f80fd5b948201945b838610156117275785358252948201949082019061170e565b9750508701359250508082111561173c575f80fd5b506117498682870161162e565b925050604084013590509250925092565b5f6020828403121561176a575f80fd5b8151611174816114af565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610a6757610a67611775565b81810381811115610a6757610a67611775565b634e487b7160e01b5f52603260045260245ffd5b5f600182016117d4576117d4611775565b5060010190565b81515f9082906020808601845b83811015611804578151855293820193908201906001016117e8565b50929695505050505050565b81515f9082906020808601845b838110156118045781516001600160a01b03168552938201939082019060010161181d565b5f60208284031215611852575f80fd5b8151611174816114de565b634e487b7160e01b5f52601260045260245ffd5b634e487b7160e01b5f52602160045260245ffd5b5f60ff8316806118a357634e487b7160e01b5f52601260045260245ffd5b8060ff8416069150509291505056fe8c5333b52aa1c4b5abeff2afd2c59c576cb9feb83f66f959574b22a3a8f8cf00cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300a2646970667358221220789386392d875d75532caf3c30c9fb02d12a3cab9cbfd0d5a08b4b4fa8ee15fd64736f6c63430008140033
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106100e5575f3560e01c80635c975abb11610088578063c4d66de811610063578063c4d66de8146101fb578063d19ec90a1461020e578063eb46260e14610221578063fbed72fa14610268575f80fd5b80635c975abb146101c95780637cb64759146101e05780638456cb59146101f3575f80fd5b806338c30fb4116100c357806338c30fb41461012c5780633f4ba83a14610186578063495906571461018e5780635c52a56f146101b5575f80fd5b806321b1d7ad146100e95780632a9a6f9c146100fe5780632fccfbd214610111575b5f80fd5b6100fc6100f73660046114c3565b61027b565b005b6100fc61010c3660046114eb565b6103d1565b6101196105b2565b6040519081526020015b60405180910390f35b61017661013a3660046114c3565b6001600160a01b03165f9081527f8c5333b52aa1c4b5abeff2afd2c59c576cb9feb83f66f959574b22a3a8f8cf07602052604090205460ff1690565b6040519015158152602001610123565b6100fc6105ca565b7f8c5333b52aa1c4b5abeff2afd2c59c576cb9feb83f66f959574b22a3a8f8cf0454610119565b6101195f805160206118b383398151915281565b5f805160206118d38339815191525460ff16610176565b6100fc6101ee366004611585565b6105f8565b6100fc61068e565b6100fc6102093660046114c3565b6106d9565b61011961021c36600461159c565b610a24565b61011961022f3660046114c3565b6001600160a01b03165f9081527f8c5333b52aa1c4b5abeff2afd2c59c576cb9feb83f66f959574b22a3a8f8cf05602052604090205490565b6100fc61027636600461169f565b610a6d565b5f5f805160206118b38339815191526001810154604051631c2d8fb360e31b81527f2efffbdded4fb417a0f132bcfde583d2d04ac8103881725f3da21929432cf4d260048201529192506001600160a01b03169063e16c7d9890602401602060405180830381865afa1580156102f3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610317919061175a565b6001600160a01b0316336001600160a01b0316146103485760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b0382165f90815260078201602052604090205460ff16156103835760405163d9eac9d960e01b815260040160405180910390fd5b6001600160a01b0382165f818152600783016020526040808220805460ff19166001179055517faca49f660bc1fd1b72001822dbb3912d5b785534ec802132a158e5b5de6197df9190a25050565b6103d9610cb0565b6103e1610cfa565b6001600160a01b0385166104085760405163e99d5ac560e01b815260040160405180910390fd5b825f03610428576040516310eb483f60e21b815260040160405180910390fd5b5f805160206118b3833981519152610444818787878787610d2c565b610461576040516309bde33960e01b815260040160405180910390fd5b6001600160a01b0386165f90815260078201602052604090205460ff161561049c5760405163d9eac9d960e01b815260040160405180910390fd5b5f806104aa8389888a610dd5565b90925090506104b98183611789565b6001600160a01b0389165f908152600585016020526040812080549091906104e2908490611789565b909155505060038301546040516340c10f1960e01b81526001600160a01b038a8116600483015260248201859052909116906340c10f19906044015f604051808303815f87803b158015610534575f80fd5b505af1158015610546573d5f803e3d5ffd5b50506040518492506001600160a01b038b1691507fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a905f90a35050506105ab60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050505050565b5f6105c56367629d206368528e2061179c565b905090565b5f805160206118b383398151915280546105ed906001600160a01b03165f610f71565b6105f5610fff565b50565b80610616576040516360a2b2e360e01b815260040160405180910390fd5b5f805160206118b38339815191528054610659906001600160a01b03167f228c42276f07752f6ef75920ba824d051df2b02ccab8e6b31f62bfaa658849d1610f71565b6004810182905560405182907f42cbc405e4dbf1b691e85b9a34b08ecfcf7a9ad9078bf4d645ccfa1fac11c10b905f90a25050565b5f805160206118b383398151915280546106d1906001600160a01b03167fe40ef4c9f0881870a532466eceeb9426f92f3b4563aab91fc873619411dc7014610f71565b6105f561105e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff165f8115801561071e5750825b90505f8267ffffffffffffffff16600114801561073a5750303b155b905081158015610748575080155b156107665760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561079057845460ff60401b1916600160401b1785555b6001600160a01b0386166107b7576040516307988a3f60e21b815260040160405180910390fd5b6107bf6110a6565b6107c76110c6565b5f5f805160206118b38339815191526001810180546001600160a01b0319166001600160a01b038a16908117909155604051631c2d8fb360e31b81527f5a92fc7720b8c2c63ba7a9aec6e2269feb0e8c23b216e4162abc2b6ed5e5a22b60048201529192509063e16c7d9890602401602060405180830381865afa158015610851573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610875919061175a565b81546001600160a01b0319166001600160a01b039182161782556001820154604051631c2d8fb360e31b81527fdbbc50039ed3ca50ec88fa75d6fe32dae25b22535afc1cd51cf4090d5ebc4d28600482015291169063e16c7d9890602401602060405180830381865afa1580156108ee573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610912919061175a565b6003820180546001600160a01b0319166001600160a01b039283161790556001820154604051631c2d8fb360e31b81527fc499adfcee6e085aaabecb4b8bbeb555bf87ab4b8b925c23c63822e6c935c4b0600482015291169063e16c7d9890602401602060405180830381865afa15801561098f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109b3919061175a565b6002820180546001600160a01b0319166001600160a01b0392909216919091179055508315610a1c57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b6001600160a01b0382165f9081527f8c5333b52aa1c4b5abeff2afd2c59c576cb9feb83f66f959574b22a3a8f8cf06602090815260408083208484529091529020545b92915050565b5f610a766110ce565b905080821080610a865750600682115b15610aa457604051632d0483c560e21b815260040160405180910390fd5b8251845114610ac6576040516308e8ba6f60e31b815260040160405180910390fd5b5f805160206118b38339815191528054610b09906001600160a01b03167f34e9d16462882c04e6106faa49ee9c90d25f46454ebf4084636951c74431b2a9610f71565b5f5b8451811015610c5457612710868281518110610b2957610b296117af565b60200260200101511115610b5057604051636b2f218360e01b815260040160405180910390fd5b816006015f868381518110610b6757610b676117af565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f8581526020019081526020015f2054868281518110610bb057610bb06117af565b602002602001015103610bd65760405163c23f6ccb60e01b815260040160405180910390fd5b858181518110610be857610be86117af565b6020026020010151826006015f878481518110610c0757610c076117af565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f205f8681526020019081526020015f20819055508080610c4c906117c3565b915050610b0b565b508285604051610c6491906117db565b604051809103902085604051610c7a9190611810565b604051908190038120907fc354b3c0578f84e812883d429ee41b8d75dfeff50ea66fa21da3b21b63aece0f905f90a45050505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00805460011901610cf457604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b5f805160206118d38339815191525460ff1615610d2a5760405163d93c066560e01b815260040160405180910390fd5b565b604080516001600160a01b038716602082015290810184905284151560608201525f90819060800160408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052805190602001209050610dc98484808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050505060048a015483611164565b98975050505050505050565b5f806367629d20421015610dfc57604051636c09fbc960e11b815260040160405180910390fd5b835f610e066110ce565b6001600160a01b038881165f81815260058c0160205260408082205460028e01549151632feaee9560e01b8152600481019490945294955090928392911690632feaee9590602401602060405180830381865afa158015610e69573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8d9190611842565b9050878015610e9a575080155b15610ece57835f03610ebf57604051636c09fbc960e11b815260040160405180910390fd5b610ecb8985600661117b565b94505b8715610ef857610ef58b8a8c84610ee5578761123a565b610ef0886001611789565b61123a565b91505b84821115610f04578491505b610f0e828661179c565b9450828511610f30576040516312d37ee560e31b815260040160405180910390fd5b610f3a838661179c565b9b919a509098505050505050505050565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b604051632474521560e21b8152600481018290523360248201526001600160a01b038316906391d1485490604401602060405180830381865afa158015610fba573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fde9190611842565b610ffb5760405163ea8e4eb560e01b815260040160405180910390fd5b5050565b611007611347565b5f805160206118d3833981519152805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b611066610cfa565b5f805160206118d3833981519152805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833611040565b6110ae611376565b5f805160206118d3833981519152805460ff19169055565b610f4b611376565b5f806040518060c0016040528063678b7ba081526020016367b45a2081526020016367d94420815260200163680222a08152602001636829afa081526020016368528e2081525090505f805b600681101561115d57828160068110611135576111356117af565b6020020151421015611148575092915050565b81611152816117c3565b92505060010161111a565b5092915050565b5f8261117085846113bf565b1490505b9392505050565b5f838302815f1985870982811083820303915050805f036111af578382816111a5576111a561185d565b0492505050611174565b8084116111cf5760405163227bc15360e01b815260040160405180910390fd5b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b5f808061124b86600160068161140b565b905060015b84811161133b576001600160a01b0386165f908152600689016020908152604080832084845290915290205415611329576001600160a01b0386165f908152600689016020908152604080832084845290915290205461270f19016112c0576112b98284611789565b9250611303565b6001600160a01b0386165f90815260068901602090815260408083208484529091528120546112f390849061271061117b565b90506112ff8185611789565b9350505b6001600160a01b0386165f90815260068901602090815260408083208484529091528120555b80611333816117c3565b915050611250565b50909695505050505050565b5f805160206118d38339815191525460ff16610d2a57604051638dfc202b60e01b815260040160405180910390fd5b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610d2a57604051631afcd79f60e31b815260040160405180910390fd5b5f81815b8451811015611403576113ef828683815181106113e2576113e26117af565b602002602001015161145a565b9150806113fb816117c3565b9150506113c3565b509392505050565b5f8061141886868661117b565b905061142383611483565b801561143e57505f84806114395761143961185d565b868809115b156114515761144e600182611789565b90505b95945050505050565b5f818310611474575f828152602084905260409020611174565b505f9182526020526040902090565b5f600282600381111561149857611498611871565b6114a29190611885565b60ff166001149050919050565b6001600160a01b03811681146105f5575f80fd5b5f602082840312156114d3575f80fd5b8135611174816114af565b80151581146105f5575f80fd5b5f805f805f608086880312156114ff575f80fd5b853561150a816114af565b9450602086013561151a816114de565b935060408601359250606086013567ffffffffffffffff8082111561153d575f80fd5b818801915088601f830112611550575f80fd5b81358181111561155e575f80fd5b8960208260051b8501011115611572575f80fd5b9699959850939650602001949392505050565b5f60208284031215611595575f80fd5b5035919050565b5f80604083850312156115ad575f80fd5b82356115b8816114af565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611603576116036115c6565b604052919050565b5f67ffffffffffffffff821115611624576116246115c6565b5060051b60200190565b5f82601f83011261163d575f80fd5b8135602061165261164d8361160b565b6115da565b82815260059290921b84018101918181019086841115611670575f80fd5b8286015b84811015611694578035611687816114af565b8352918301918301611674565b509695505050505050565b5f805f606084860312156116b1575f80fd5b833567ffffffffffffffff808211156116c8575f80fd5b818601915086601f8301126116db575f80fd5b813560206116eb61164d8361160b565b82815260059290921b8401810191818101908a841115611709575f80fd5b948201945b838610156117275785358252948201949082019061170e565b9750508701359250508082111561173c575f80fd5b506117498682870161162e565b925050604084013590509250925092565b5f6020828403121561176a575f80fd5b8151611174816114af565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610a6757610a67611775565b81810381811115610a6757610a67611775565b634e487b7160e01b5f52603260045260245ffd5b5f600182016117d4576117d4611775565b5060010190565b81515f9082906020808601845b83811015611804578151855293820193908201906001016117e8565b50929695505050505050565b81515f9082906020808601845b838110156118045781516001600160a01b03168552938201939082019060010161181d565b5f60208284031215611852575f80fd5b8151611174816114de565b634e487b7160e01b5f52601260045260245ffd5b634e487b7160e01b5f52602160045260245ffd5b5f60ff8316806118a357634e487b7160e01b5f52601260045260245ffd5b8060ff8416069150509291505056fe8c5333b52aa1c4b5abeff2afd2c59c576cb9feb83f66f959574b22a3a8f8cf00cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300a2646970667358221220789386392d875d75532caf3c30c9fb02d12a3cab9cbfd0d5a08b4b4fa8ee15fd64736f6c63430008140033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.