Source Code
Latest 25 from a total of 54,256 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Harvest Pool | 59305137 | 227 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 55744506 | 258 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 54402851 | 270 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 53603537 | 277 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 52192347 | 290 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 52107813 | 292 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 52074682 | 293 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51869791 | 296 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51843592 | 297 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51819299 | 297 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51787314 | 297 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51783017 | 298 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51765099 | 298 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51733591 | 298 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51733535 | 298 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51712663 | 299 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51704616 | 299 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51704446 | 299 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51699598 | 299 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51679730 | 299 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51679190 | 299 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51677006 | 299 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51676462 | 299 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51676446 | 299 days ago | IN | 0 BNB | 0.00000979 | ||||
| Harvest Pool | 51676285 | 299 days ago | IN | 0 BNB | 0.00000979 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 59305137 | 227 days ago | 2.98824515 BNB | ||||
| 55744506 | 258 days ago | 2.98824515 BNB | ||||
| 54402851 | 270 days ago | 2.98824515 BNB | ||||
| 53603537 | 277 days ago | 2.98824515 BNB | ||||
| 52192347 | 290 days ago | 1.45055118 BNB | ||||
| 52107813 | 292 days ago | 2.98824515 BNB | ||||
| 52074682 | 293 days ago | 2.98824515 BNB | ||||
| 51869791 | 296 days ago | 0.00137719 BNB | ||||
| 51843592 | 297 days ago | 2.98824515 BNB | ||||
| 51819299 | 297 days ago | 2.98824515 BNB | ||||
| 51787314 | 297 days ago | 2.98824515 BNB | ||||
| 51783017 | 298 days ago | 2.98824515 BNB | ||||
| 51765099 | 298 days ago | 2.98724143 BNB | ||||
| 51733591 | 298 days ago | 0.01052719 BNB | ||||
| 51733535 | 298 days ago | 2.98824515 BNB | ||||
| 51712663 | 299 days ago | 2.98824515 BNB | ||||
| 51704616 | 299 days ago | 2.98824515 BNB | ||||
| 51704446 | 299 days ago | 2.97848853 BNB | ||||
| 51699598 | 299 days ago | 2.98824515 BNB | ||||
| 51679730 | 299 days ago | 2.98824515 BNB | ||||
| 51679190 | 299 days ago | 2.98824515 BNB | ||||
| 51677006 | 299 days ago | 2.98824515 BNB | ||||
| 51676462 | 299 days ago | 2.98824515 BNB | ||||
| 51676446 | 299 days ago | 2.98824515 BNB | ||||
| 51676285 | 299 days ago | 2.98824515 BNB |
Cross-Chain Transactions
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x60a8Cf71...9c4581DAE The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
IDOInitializableV3
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin-4.5.0/contracts/access/Ownable.sol";
import {ERC20} from "solmate/src/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {SafeCastLib} from "solmate/src/utils/SafeCastLib.sol";
import {ECDSA} from "@openzeppelin-4.5.0/contracts/utils/cryptography/ECDSA.sol";
import {ReentrancyGuardTransient} from "../base/ReentrancyGuardTransient.sol";
/**
* @title IDOInitializableV3
* @notice IDOv3 supports 1 or 2 pools -- each pool can raise in their own lpToken (eg. BNB or CAKE)
*/
contract IDOInitializableV3 is Ownable, ReentrancyGuardTransient {
using SafeTransferLib for ERC20;
using SafeTransferLib for address;
using SafeCastLib for uint256;
// Whether it is initialized
bool private isInitialized;
// all the addresses
// [0] lpToken0 [1] lpToken1 [2] offeringToken [3] adminAddress
address[4] public addresses;
// The timestamp when IDO starts
uint256 public startTimestamp;
// The timestamp when IDO ends
uint256 public endTimestamp;
// Max buffer seconds (for sanity checks)
uint256 public MAX_BUFFER_SECONDS;
// Max pool id (0 if only 1 pool, 1 if theres 2 pools)
uint8 public MAX_POOL_ID;
// Minimum amount for each user to deposit into the pool
uint256[2] public MIN_DEPOSIT_AMOUNTS;
// Total tokens distributed across the pools
uint256 public totalTokensOffered;
// Struct that contains pool's information
struct PoolInformation {
uint128 raisingAmountPool; // amount of tokens raised for the pool (in LP tokens)
uint128 offeringAmountPool; // amount of tokens offered for the pool (in offeringTokens)
uint128 capPerUserInLP; // cap of tokens per user (if 0, it is ignored)
uint128 totalAmountPool; // total amount pool deposited (in LP tokens)
}
// Array of PoolInformation of size NUMBER_POOLS
PoolInformation[2] public _poolInformation;
// Struct that contains each user information for both pools
struct UserInfo {
uint128 amountPool; // How many tokens the user has provided for pool
bool claimedPool; // Whether the user has claimed (default: false) for pool
}
// It maps the address to pool id to UserInfo
mapping(address => mapping(uint8 => UserInfo)) private _userInfo;
// An address for the signer of the signature
address public signerAddress;
// Admin withdraw events
event AdminWithdraw(uint256 amountLP0, uint256 amountLP1, uint256 amountOfferingToken);
// Admin recovers token
event AdminTokenRecovery(address tokenAddress, uint256 amountTokens);
// Deposit event
event Deposit(address indexed user, uint256 amount, uint8 indexed pid);
// Harvest event
event Harvest(address indexed user, uint256 offeringAmount, uint256 excessAmount, uint8 indexed pid);
// Event for new start & end timestamps
event NewStartAndEndTimestamps(uint256 startTimestamp, uint256 endTimestamp);
// Event when parameters are set for one of the pools
event PoolParametersSet(uint256 offeringAmountPool, uint256 raisingAmountPool, uint8 indexed pid);
// Event when MIN_DEPOSIT_AMOUNT is updated
event UpdatedMinDepositAmount(uint256 minAmount, uint8 indexed pid);
// Event when signer address update
event UpdatedSignerAddress(address indexed signerAddr);
error MaxPoolIdNotValid();
error PoolIdNotValid();
error SignatureVerifyFailed();
error SignerAddressZero();
error EndTimeTooFar();
error StartTimeMustInferiorToEndTime();
error AlreadyInitialized();
error AddressesLengthNotCorrect();
error StartAndEndTimestampsLengthNotCorrect();
error TokensNotDepositedProperly();
error NewAmountAboveUserCap();
error CanNotBeLPToken();
error CanNotBeOfferingToken();
error PoolNotSet();
error TooEarly();
error TooLate();
error AmountMustBeZero();
error AmountMustExceedZero();
error AmountMustExceedMinimum();
error DidNotParticipate();
error AlreadyHarvested();
error NotEnoughLPTokens();
error NotEnoughOfferingTokens();
error IDOHasStarted();
/**
* @notice Constructor
*/
constructor() {
MIN_DEPOSIT_AMOUNTS[0] = 1000000;
MIN_DEPOSIT_AMOUNTS[1] = 1000000;
}
/**
* @notice It initializes the contract
* @dev It can only be called once.
* @dev no caller check as this method is called immediately after contract is created
* @param _addresses: [0] lpToken0 [1] lpToken1 [2] offeringToken [3] adminAddress
* @param _startAndEndTimestamps: [0] startTimestamp [1] endTimestamp
* @param _maxBufferSeconds: maximum buffer of blocks from the current block number
* @param _maxPoolId: maximum id of pools, if it is 0 means 1 pool, and 1 means 2 pools
*/
function initialize(
address[] calldata _addresses,
uint256[] calldata _startAndEndTimestamps,
uint256 _maxBufferSeconds,
uint8 _maxPoolId
) public {
if (isInitialized) {
revert AlreadyInitialized();
}
if (_addresses.length != 4) {
revert AddressesLengthNotCorrect();
}
if (_startAndEndTimestamps.length != 2) {
revert StartAndEndTimestampsLengthNotCorrect();
}
// Make this contract initialized
isInitialized = true;
// [0] lpToken0
// [1] lpToken1
// [2] offeringToken
// [3] adminAddress
for (uint8 i = 0; i < _addresses.length; i++) {
addresses[i] = _addresses[i];
}
startTimestamp = _startAndEndTimestamps[0];
endTimestamp = _startAndEndTimestamps[1];
MAX_BUFFER_SECONDS = _maxBufferSeconds;
if (_maxPoolId <= 1) {
MAX_POOL_ID = _maxPoolId;
} else {
revert MaxPoolIdNotValid();
}
// Transfer ownership to admin
transferOwnership(_addresses[3]);
}
/**
* @notice It allows users to deposit LP tokens to pool
* @dev if the LP address is Zero, means user should deposit Native token instead of ERC20
* @param _amount: the number of LP token used (18 decimals) - if address[0] == address(0), IDO is raising in native token, thus this parameter will not be used
* @param _pid: pool id
* @param _expiredAt: the expire timestamp at
* @param _signature: the signature string to verify it is from msg.sender
*/
function depositPool(uint256 _amount, uint8 _pid, uint256 _expiredAt, bytes memory _signature)
external
payable
nonReentrant
{
_checkPid(_pid);
// Checks signature is correct
// we don't use chainId so can be replayed on multiple chains if the address is the same,
// but that is quite unlikely since the salt should be different for different ido sale tokens
bytes32 msgHash = keccak256(abi.encode(address(this), "VerifyAddress", msg.sender, _expiredAt));
address addr = ECDSA.recover(ECDSA.toEthSignedMessageHash(msgHash), _signature);
if (block.timestamp > _expiredAt || addr != signerAddress) {
revert SignatureVerifyFailed();
}
// Checks that pool was set
if (_poolInformation[_pid].offeringAmountPool == 0 || _poolInformation[_pid].raisingAmountPool == 0) {
revert PoolNotSet();
}
// Checks whether the timestamp is not too early
if (block.timestamp < startTimestamp) {
revert TooEarly();
}
// Checks whether the timestamp is not too late
if (block.timestamp > endTimestamp) {
revert TooLate();
}
// Verify tokens were deposited properly
if (ERC20(addresses[2]).balanceOf(address(this)) < totalTokensOffered) {
revert TokensNotDepositedProperly();
}
uint128 transferAmount;
// Checks that the amount deposited is not inferior to 0
if (addresses[_pid] == address(0)) {
if (msg.value == 0) {
revert AmountMustExceedZero();
}
transferAmount = msg.value.safeCastTo128();
} else {
if (msg.value != 0) {
revert AmountMustBeZero();
}
if (_amount == 0) {
revert AmountMustExceedZero();
}
// Transfers funds to this contract
ERC20(addresses[_pid]).safeTransferFrom(msg.sender, address(this), _amount);
transferAmount = _amount.safeCastTo128();
}
// Update the user status
_userInfo[msg.sender][_pid].amountPool = _userInfo[msg.sender][_pid].amountPool + transferAmount;
if (_userInfo[msg.sender][_pid].amountPool < MIN_DEPOSIT_AMOUNTS[_pid]) {
revert AmountMustExceedMinimum();
}
// Check if the pool has a cap per user
if (_poolInformation[_pid].capPerUserInLP > 0) {
// Checks whether the cap has been reached
if (_userInfo[msg.sender][_pid].amountPool > _poolInformation[_pid].capPerUserInLP) {
revert NewAmountAboveUserCap();
}
}
// Updates the totalAmount for pool
_poolInformation[_pid].totalAmountPool = _poolInformation[_pid].totalAmountPool + transferAmount;
emit Deposit(msg.sender, transferAmount, _pid);
}
/**
* @notice It allows users to harvest from pool
* @param _pid: pool id
*/
function harvestPool(uint8 _pid) external nonReentrant {
_checkPid(_pid);
// Checks whether pool id is valid
if (block.timestamp <= endTimestamp) {
revert TooEarly();
}
// Checks whether the user has participated
if (_userInfo[msg.sender][_pid].amountPool == 0) {
revert DidNotParticipate();
}
// Checks whether the user has already harvested
if (_userInfo[msg.sender][_pid].claimedPool) {
revert AlreadyHarvested();
}
// Updates the harvest status
_userInfo[msg.sender][_pid].claimedPool = true;
(uint256 offeringTokenAmount, uint256 refundingTokenAmount) =
_calculateOfferingAndRefundingAmountsPool(msg.sender, _pid);
// Transfer these tokens back to the user if quantity > 0
if (offeringTokenAmount > 0) {
// Transfer the tokens at TGE
ERC20(addresses[2]).safeTransfer(msg.sender, offeringTokenAmount);
}
if (refundingTokenAmount > 0) {
if (addresses[_pid] == address(0)) {
msg.sender.safeTransferETH(refundingTokenAmount);
} else {
ERC20(addresses[_pid]).safeTransfer(msg.sender, refundingTokenAmount);
}
}
emit Harvest(msg.sender, offeringTokenAmount, refundingTokenAmount, _pid);
}
/**
* @notice It allows the admin to withdraw funds
* @param _lpAmount0: the number of LP token0 to withdraw (18 decimals)
* @param _lpAmount1: the number of LP token1 to withdraw (18 decimals)
* @param _offerAmount: the number of offering amount to withdraw
* @dev This function is only callable by admin.
*/
function finalWithdraw(uint256 _lpAmount0, uint256 _lpAmount1, uint256 _offerAmount) external onlyOwner {
if (_lpAmount0 > 0) {
if (addresses[0] == address(0)) {
msg.sender.safeTransferETH(_lpAmount0);
} else {
_safeTransferLpToken(msg.sender, _lpAmount0, 0);
}
}
if (_lpAmount1 > 0) {
if (addresses[1] == address(0)) {
msg.sender.safeTransferETH(_lpAmount1);
} else {
_safeTransferLpToken(msg.sender, _lpAmount1, 1);
}
}
if (_offerAmount > 0) {
ERC20(addresses[2]).safeTransfer(msg.sender, _offerAmount);
}
emit AdminWithdraw(_lpAmount0, _lpAmount1, _offerAmount);
}
/**
* @notice It allows the admin to recover wrong tokens sent to the contract
* @param _tokenAddress: the address of the token to withdraw (18 decimals)
* @param _tokenAmount: the number of token amount to withdraw
* @dev This function is only callable by admin.
*/
function recoverWrongTokens(address _tokenAddress, uint256 _tokenAmount) external onlyOwner {
if (_tokenAddress == addresses[0]) {
revert CanNotBeLPToken();
}
if (_tokenAddress == addresses[1]) {
revert CanNotBeLPToken();
}
if (_tokenAddress == addresses[2]) {
revert CanNotBeOfferingToken();
}
ERC20(_tokenAddress).safeTransfer(msg.sender, _tokenAmount);
emit AdminTokenRecovery(_tokenAddress, _tokenAmount);
}
/**
* @notice It sets parameters for pool
* @param _offeringAmountPool: offering amount (in tokens)
* @param _raisingAmountPool: raising amount (in LP tokens)
* @param _limitPerUserInLP: limit per user (in LP tokens)
* @param _pid: pool id
*/
function setPool(uint256 _offeringAmountPool, uint256 _raisingAmountPool, uint256 _limitPerUserInLP, uint8 _pid)
external
onlyOwner
{
_checkPid(_pid);
if (block.timestamp >= startTimestamp) {
revert IDOHasStarted();
}
_poolInformation[_pid].offeringAmountPool = _offeringAmountPool.safeCastTo128();
_poolInformation[_pid].raisingAmountPool = _raisingAmountPool.safeCastTo128();
_poolInformation[_pid].capPerUserInLP = _limitPerUserInLP.safeCastTo128();
uint256 tokensDistributedAcrossPools;
for (uint8 i = 0; i <= MAX_POOL_ID; i++) {
tokensDistributedAcrossPools = tokensDistributedAcrossPools + _poolInformation[i].offeringAmountPool;
}
// Update totalTokensOffered
totalTokensOffered = tokensDistributedAcrossPools;
emit PoolParametersSet(_offeringAmountPool, _raisingAmountPool, _pid);
}
/**
* @notice It allows the admin to update start and end blocks
* @param _startAndEndTimestamps: [0] startTimestamp [1] endTimestamp
* @dev This function is only callable by admin.
*/
function updateStartAndEndTimestamps(uint256[] calldata _startAndEndTimestamps) external onlyOwner {
if (_startAndEndTimestamps.length != 2) {
revert StartAndEndTimestampsLengthNotCorrect();
}
if (endTimestamp >= (block.timestamp + MAX_BUFFER_SECONDS)) revert EndTimeTooFar();
if (startTimestamp >= endTimestamp) revert StartTimeMustInferiorToEndTime();
if (block.timestamp >= startTimestamp) revert IDOHasStarted();
startTimestamp = _startAndEndTimestamps[0];
endTimestamp = _startAndEndTimestamps[1];
emit NewStartAndEndTimestamps(_startAndEndTimestamps[0], _startAndEndTimestamps[1]);
}
/**
* @notice It allows the admin to update MIN_DEPOSIT_AMOUNT
* @param _newAmount The new value of minimum amount
* @param _pid: pool id
* @dev This function is only callable by admin.
*/
function updateMinDepositAmount(uint256 _newAmount, uint8 _pid) external onlyOwner {
_checkPid(_pid);
MIN_DEPOSIT_AMOUNTS[_pid] = _newAmount;
emit UpdatedMinDepositAmount(_newAmount, _pid);
}
/**
* @notice It allows the admin to update the signer address
* @param _signerAddr: the signer address for the signature verification
* @dev This function is only callable by admin.
*/
function updateSignerAddress(address _signerAddr) external onlyOwner {
if (_signerAddr == address(0)) revert SignerAddressZero();
signerAddress = _signerAddr;
emit UpdatedSignerAddress(_signerAddr);
}
/**
* @notice External view function to see user allocations for pool
* @param _user: user address
* @param _pids[]: array of pids
* @return
*/
function viewUserAllocationPools(address _user, uint8[] calldata _pids) public view returns (uint256[] memory) {
uint256[] memory allocationPools = new uint256[](_pids.length);
for (uint8 i = 0; i < _pids.length; i++) {
allocationPools[i] = _getUserAllocationPool(_user, _pids[i]);
}
return allocationPools;
}
/**
* @notice External view function to see user information
* @param _user: user address
* @param _pids[]: array of pids
*/
function viewUserInfo(address _user, uint8[] calldata _pids)
external
view
returns (uint256[] memory, bool[] memory)
{
uint256[] memory amountPools = new uint256[](_pids.length);
bool[] memory statusPools = new bool[](_pids.length);
for (uint8 i = 0; i < _pids.length; i++) {
uint8 pid = _pids[i];
if (pid <= MAX_POOL_ID) {
amountPools[i] = _userInfo[_user][pid].amountPool;
statusPools[i] = _userInfo[_user][pid].claimedPool;
}
}
return (amountPools, statusPools);
}
/**
* @notice External view function to see user offering and refunding amounts for pool
* @param _user: user address
* @param _pids: array of pids
*/
function viewUserOfferingAndRefundingAmountsForPools(address _user, uint8[] calldata _pids)
public
view
returns (uint256[2][] memory)
{
uint256[2][] memory amountPools = new uint256[2][](_pids.length);
for (uint8 i = 0; i < _pids.length; i++) {
uint256 userOfferingAmountPool;
uint256 userRefundingAmountPool;
if (_poolInformation[_pids[i]].raisingAmountPool > 0) {
(userOfferingAmountPool, userRefundingAmountPool) =
_calculateOfferingAndRefundingAmountsPool(_user, _pids[i]);
}
amountPools[i] = [userOfferingAmountPool, userRefundingAmountPool];
}
return amountPools;
}
/**
* @notice It calculates the offering amount for a user and the number of LP tokens to transfer back.
* @param _user: user address
* @param _pid: pool id
* @return userOfferingAmount the amount of offering tokens user will get
* @return userRefundingAmount the amount of refunding (eg. BNB) token user will get
*/
function _calculateOfferingAndRefundingAmountsPool(address _user, uint8 _pid)
internal
view
returns (uint256 userOfferingAmount, uint256 userRefundingAmount)
{
uint256 userAmountInPool = _userInfo[_user][_pid].amountPool;
uint256 raisingAmountInPool = _poolInformation[_pid].raisingAmountPool;
if (_poolInformation[_pid].totalAmountPool > raisingAmountInPool) {
// Calculate allocation for the user
uint256 allocation = _getUserAllocationPool(_user, _pid);
// Calculate the offering amount for the user based on the offeringAmount for the pool
userOfferingAmount = (_poolInformation[_pid].offeringAmountPool * allocation) / 1e12;
// Calculate the payAmount
uint256 payAmount = (raisingAmountInPool * allocation) / 1e12;
// Calculate the pre-tax refunding amount
userRefundingAmount = userAmountInPool - payAmount;
} else {
// _userInfo[_user] / (raisingAmount / offeringAmount)
userOfferingAmount = (userAmountInPool * _poolInformation[_pid].offeringAmountPool) / raisingAmountInPool;
if (userOfferingAmount == 0 && userAmountInPool > 0) {
userRefundingAmount = userAmountInPool;
}
}
}
/**
* @notice It returns the user allocation for pool
* @dev 100,000,000,000 means 0.1 (10%) / 1 means 0.0000000000001 (0.0000001%) / 1,000,000,000,000 means 1 (100%)
* @param _user: user address
* @param _pid: pool id
* @return It returns the user's share of pool
*/
function _getUserAllocationPool(address _user, uint8 _pid) internal view returns (uint256) {
if (_pid > MAX_POOL_ID) {
return 0;
}
if (_poolInformation[_pid].totalAmountPool > 0) {
return (_userInfo[_user][_pid].amountPool * 1e12) / _poolInformation[_pid].totalAmountPool;
} else {
return 0;
}
}
function _checkPid(uint8 _pid) internal view {
if (_pid > MAX_POOL_ID) {
revert PoolIdNotValid();
}
}
function _checkLpTokenBalance(uint256 _amount, uint256 _balance) internal pure {
if (_amount > _balance) {
revert NotEnoughLPTokens();
}
}
function _safeTransferLpToken(address _to, uint256 _amount, uint8 _pid) internal {
_checkPid(_pid);
ERC20(addresses[_pid]).safeTransfer(_to, _amount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
success := call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data and token has code.
if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) {
success := iszero(or(iszero(extcodesize(token)), returndatasize()))
}
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
success := call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data and token has code.
if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) {
success := iszero(or(iszero(extcodesize(token)), returndatasize()))
}
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
success := call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data and token has code.
if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) {
success := iszero(or(iszero(extcodesize(token)), returndatasize()))
}
}
require(success, "APPROVE_FAILED");
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Safe unsigned integer casting library that reverts on overflow.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol)
library SafeCastLib {
function safeCastTo248(uint256 x) internal pure returns (uint248 y) {
require(x < 1 << 248);
y = uint248(x);
}
function safeCastTo240(uint256 x) internal pure returns (uint240 y) {
require(x < 1 << 240);
y = uint240(x);
}
function safeCastTo232(uint256 x) internal pure returns (uint232 y) {
require(x < 1 << 232);
y = uint232(x);
}
function safeCastTo224(uint256 x) internal pure returns (uint224 y) {
require(x < 1 << 224);
y = uint224(x);
}
function safeCastTo216(uint256 x) internal pure returns (uint216 y) {
require(x < 1 << 216);
y = uint216(x);
}
function safeCastTo208(uint256 x) internal pure returns (uint208 y) {
require(x < 1 << 208);
y = uint208(x);
}
function safeCastTo200(uint256 x) internal pure returns (uint200 y) {
require(x < 1 << 200);
y = uint200(x);
}
function safeCastTo192(uint256 x) internal pure returns (uint192 y) {
require(x < 1 << 192);
y = uint192(x);
}
function safeCastTo184(uint256 x) internal pure returns (uint184 y) {
require(x < 1 << 184);
y = uint184(x);
}
function safeCastTo176(uint256 x) internal pure returns (uint176 y) {
require(x < 1 << 176);
y = uint176(x);
}
function safeCastTo168(uint256 x) internal pure returns (uint168 y) {
require(x < 1 << 168);
y = uint168(x);
}
function safeCastTo160(uint256 x) internal pure returns (uint160 y) {
require(x < 1 << 160);
y = uint160(x);
}
function safeCastTo152(uint256 x) internal pure returns (uint152 y) {
require(x < 1 << 152);
y = uint152(x);
}
function safeCastTo144(uint256 x) internal pure returns (uint144 y) {
require(x < 1 << 144);
y = uint144(x);
}
function safeCastTo136(uint256 x) internal pure returns (uint136 y) {
require(x < 1 << 136);
y = uint136(x);
}
function safeCastTo128(uint256 x) internal pure returns (uint128 y) {
require(x < 1 << 128);
y = uint128(x);
}
function safeCastTo120(uint256 x) internal pure returns (uint120 y) {
require(x < 1 << 120);
y = uint120(x);
}
function safeCastTo112(uint256 x) internal pure returns (uint112 y) {
require(x < 1 << 112);
y = uint112(x);
}
function safeCastTo104(uint256 x) internal pure returns (uint104 y) {
require(x < 1 << 104);
y = uint104(x);
}
function safeCastTo96(uint256 x) internal pure returns (uint96 y) {
require(x < 1 << 96);
y = uint96(x);
}
function safeCastTo88(uint256 x) internal pure returns (uint88 y) {
require(x < 1 << 88);
y = uint88(x);
}
function safeCastTo80(uint256 x) internal pure returns (uint80 y) {
require(x < 1 << 80);
y = uint80(x);
}
function safeCastTo72(uint256 x) internal pure returns (uint72 y) {
require(x < 1 << 72);
y = uint72(x);
}
function safeCastTo64(uint256 x) internal pure returns (uint64 y) {
require(x < 1 << 64);
y = uint64(x);
}
function safeCastTo56(uint256 x) internal pure returns (uint56 y) {
require(x < 1 << 56);
y = uint56(x);
}
function safeCastTo48(uint256 x) internal pure returns (uint48 y) {
require(x < 1 << 48);
y = uint48(x);
}
function safeCastTo40(uint256 x) internal pure returns (uint40 y) {
require(x < 1 << 40);
y = uint40(x);
}
function safeCastTo32(uint256 x) internal pure returns (uint32 y) {
require(x < 1 << 32);
y = uint32(x);
}
function safeCastTo24(uint256 x) internal pure returns (uint24 y) {
require(x < 1 << 24);
y = uint24(x);
}
function safeCastTo16(uint256 x) internal pure returns (uint16 y) {
require(x < 1 << 16);
y = uint16(x);
}
function safeCastTo8(uint256 x) internal pure returns (uint8 y) {
require(x < 1 << 8);
y = uint8(x);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
// Check the signature length
// - case 65: r,s,v signature (standard)
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// @notice Using transient storage slot for the lock status
/// @dev credit to https://github.com/Vectorized/solady/blob/main/src/utils/ReentrancyGuardTransient.sol
abstract contract ReentrancyGuardTransient {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Unauthorized reentrant call.
error Reentrancy();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to: `uint32(bytes4(keccak256("Reentrancy()"))) | 1 << 71`.
/// 9 bytes is large enough to avoid collisions in practice,
/// but not too large to result in excessive bytecode bloat.
uint256 private constant _REENTRANCY_GUARD_SLOT = 0x8000000000ab143c06;
modifier nonReentrant() {
/// @solidity memory-safe-assembly
assembly {
if tload(_REENTRANCY_GUARD_SLOT) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
tstore(_REENTRANCY_GUARD_SLOT, address())
}
_;
/// @solidity memory-safe-assembly
assembly {
tstore(_REENTRANCY_GUARD_SLOT, 0)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}{
"remappings": [
"@openzeppelin-4.5.0/=lib/openzeppelin-contracts/",
"solmate/=lib/solmate/",
"ds-test/=lib/solmate/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressesLengthNotCorrect","type":"error"},{"inputs":[],"name":"AlreadyHarvested","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AmountMustBeZero","type":"error"},{"inputs":[],"name":"AmountMustExceedMinimum","type":"error"},{"inputs":[],"name":"AmountMustExceedZero","type":"error"},{"inputs":[],"name":"CanNotBeLPToken","type":"error"},{"inputs":[],"name":"CanNotBeOfferingToken","type":"error"},{"inputs":[],"name":"DidNotParticipate","type":"error"},{"inputs":[],"name":"EndTimeTooFar","type":"error"},{"inputs":[],"name":"IDOHasStarted","type":"error"},{"inputs":[],"name":"MaxPoolIdNotValid","type":"error"},{"inputs":[],"name":"NewAmountAboveUserCap","type":"error"},{"inputs":[],"name":"NotEnoughLPTokens","type":"error"},{"inputs":[],"name":"NotEnoughOfferingTokens","type":"error"},{"inputs":[],"name":"PoolIdNotValid","type":"error"},{"inputs":[],"name":"PoolNotSet","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"SignatureVerifyFailed","type":"error"},{"inputs":[],"name":"SignerAddressZero","type":"error"},{"inputs":[],"name":"StartAndEndTimestampsLengthNotCorrect","type":"error"},{"inputs":[],"name":"StartTimeMustInferiorToEndTime","type":"error"},{"inputs":[],"name":"TokensNotDepositedProperly","type":"error"},{"inputs":[],"name":"TooEarly","type":"error"},{"inputs":[],"name":"TooLate","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountTokens","type":"uint256"}],"name":"AdminTokenRecovery","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountLP0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountLP1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOfferingToken","type":"uint256"}],"name":"AdminWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"pid","type":"uint8"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"offeringAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"excessAmount","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"pid","type":"uint8"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTimestamp","type":"uint256"}],"name":"NewStartAndEndTimestamps","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"offeringAmountPool","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"raisingAmountPool","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"pid","type":"uint8"}],"name":"PoolParametersSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minAmount","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"pid","type":"uint8"}],"name":"UpdatedMinDepositAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signerAddr","type":"address"}],"name":"UpdatedSignerAddress","type":"event"},{"inputs":[],"name":"MAX_BUFFER_SECONDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_POOL_ID","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MIN_DEPOSIT_AMOUNTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"_poolInformation","outputs":[{"internalType":"uint128","name":"raisingAmountPool","type":"uint128"},{"internalType":"uint128","name":"offeringAmountPool","type":"uint128"},{"internalType":"uint128","name":"capPerUserInLP","type":"uint128"},{"internalType":"uint128","name":"totalAmountPool","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"addresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint8","name":"_pid","type":"uint8"},{"internalType":"uint256","name":"_expiredAt","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"depositPool","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"endTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lpAmount0","type":"uint256"},{"internalType":"uint256","name":"_lpAmount1","type":"uint256"},{"internalType":"uint256","name":"_offerAmount","type":"uint256"}],"name":"finalWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_pid","type":"uint8"}],"name":"harvestPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addresses","type":"address[]"},{"internalType":"uint256[]","name":"_startAndEndTimestamps","type":"uint256[]"},{"internalType":"uint256","name":"_maxBufferSeconds","type":"uint256"},{"internalType":"uint8","name":"_maxPoolId","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"recoverWrongTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_offeringAmountPool","type":"uint256"},{"internalType":"uint256","name":"_raisingAmountPool","type":"uint256"},{"internalType":"uint256","name":"_limitPerUserInLP","type":"uint256"},{"internalType":"uint8","name":"_pid","type":"uint8"}],"name":"setPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokensOffered","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newAmount","type":"uint256"},{"internalType":"uint8","name":"_pid","type":"uint8"}],"name":"updateMinDepositAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signerAddr","type":"address"}],"name":"updateSignerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_startAndEndTimestamps","type":"uint256[]"}],"name":"updateStartAndEndTimestamps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint8[]","name":"_pids","type":"uint8[]"}],"name":"viewUserAllocationPools","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint8[]","name":"_pids","type":"uint8[]"}],"name":"viewUserInfo","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint8[]","name":"_pids","type":"uint8[]"}],"name":"viewUserOfferingAndRefundingAmountsForPools","outputs":[{"internalType":"uint256[2][]","name":"","type":"uint256[2][]"}],"stateMutability":"view","type":"function"}]Contract Creation Code
0x6080604052348015600e575f80fd5b506016336026565b620f42406009819055600a556075565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6126fe806100825f395ff3fe608060405260043610610147575f3560e01c8063a85adeab116100b3578063dfd2bb551161006d578063dfd2bb55146103c8578063e6fd48bc146103e7578063edf26d9b146103fc578063f2fde38b1461041b578063f93bf8331461043a578063f9cd5c1214610459575f80fd5b8063a85adeab146102d8578063b1ced5e7146102ed578063c8aa65c114610318578063ca463ca41461032b578063caa7f23214610357578063ce3f5e4b14610376575f80fd5b80635b7633d0116101045780635b7633d01461021e578063715018a614610255578063760b31801461026957806376920d081461027e5780638da5cb5b1461029d5780638fa2a9f0146102b9575f80fd5b80630f0b7a2b1461014b5780632374876c1461017d5780632937049e1461019e5780633f138d4b146101bd5780634af3c9b7146101dc57806354070e3914610209575b5f80fd5b348015610156575f80fd5b5061016a6101653660046120c8565b610485565b6040519081526020015b60405180910390f35b348015610188575f80fd5b5061019c6101973660046120f4565b61049b565b005b3480156101a9575f80fd5b5061019c6101b8366004612114565b610681565b3480156101c8575f80fd5b5061019c6101d7366004612153565b61076e565b3480156101e7575f80fd5b506101fb6101f63660046121bc565b61087f565b604051610174929190612245565b348015610214575f80fd5b5061016a60075481565b348015610229575f80fd5b5060115461023d906001600160a01b031681565b6040516001600160a01b039091168152602001610174565b348015610260575f80fd5b5061019c610a26565b348015610274575f80fd5b5061016a600b5481565b348015610289575f80fd5b5061019c61029836600461229f565b610a5a565b3480156102a8575f80fd5b505f546001600160a01b031661023d565b3480156102c4575f80fd5b5061019c6102d33660046122db565b610c20565b3480156102e3575f80fd5b5061016a60065481565b3480156102f8575f80fd5b506008546103069060ff1681565b60405160ff9091168152602001610174565b61019c610326366004612308565b610cb9565b348015610336575f80fd5b5061034a6103453660046121bc565b61121e565b60405161017491906123de565b348015610362575f80fd5b5061019c610371366004612447565b611365565b348015610381575f80fd5b506103956103903660046120c8565b6114c9565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610174565b3480156103d3575f80fd5b5061019c6103e2366004612486565b611506565b3480156103f2575f80fd5b5061016a60055481565b348015610407575f80fd5b5061023d6104163660046120c8565b6116ae565b348015610426575f80fd5b5061019c6104353660046122db565b6116cd565b348015610445575f80fd5b5061019c61045436600461250d565b611767565b348015610464575f80fd5b506104786104733660046121bc565b6117ee565b6040516101749190612537565b60098160028110610494575f80fd5b0154905081565b688000000000ab143c065c156104b85763ab143c065f526004601cfd5b30688000000000ab143c065d6104cd816118a8565b60065442116104ef5760405163085de62560e01b815260040160405180910390fd5b335f90815260106020908152604080832060ff851684529091528120546001600160801b03169003610534576040516337191a8560e21b815260040160405180910390fd5b335f90815260106020908152604080832060ff8086168552925290912054600160801b90041615610578576040516302cce53760e21b815260040160405180910390fd5b335f81815260106020908152604080832060ff861684529091528120805460ff60801b1916600160801b1790559081906105b290846118d2565b909250905081156105d9576105d93383600160025b01546001600160a01b03169190611a58565b8015610630575f600160ff8516600481106105f6576105f6612549565b01546001600160a01b031603610615576106103382611ae7565b610630565b610630338260018660ff16600481106105c7576105c7612549565b604080518381526020810183905260ff85169133917f51524c2e5edfedf8b01b29719c661e4fbe27e71734e7cd773dabb7cb712fb3b3910160405180910390a350505f688000000000ab143c065d50565b5f546001600160a01b031633146106b35760405162461bcd60e51b81526004016106aa9061255d565b60405180910390fd5b82156106e3576001546001600160a01b03166106d8576106d33384611ae7565b6106e3565b6106e333845f611b3a565b8115610714576002546001600160a01b0316610708576107033383611ae7565b610714565b61071433836001611b3a565b8015610728576107283382600160026105c7565b60408051848152602081018490529081018290527f5cba002c3841a6704789c1f41f4dab171dc5a8c972c928498c961665cdecf41b9060600160405180910390a1505050565b5f546001600160a01b031633146107975760405162461bcd60e51b81526004016106aa9061255d565b6001546001600160a01b03908116908316036107c6576040516310da472360e01b815260040160405180910390fd5b6002546001600160a01b03908116908316036107f5576040516310da472360e01b815260040160405180910390fd5b6003546001600160a01b03908116908316036108245760405163a8dfadb960e01b815260040160405180910390fd5b6108386001600160a01b0383163383611a58565b604080516001600160a01b0384168152602081018390527f74545154aac348a3eac92596bd1971957ca94795f4e954ec5f613b55fab7812991015b60405180910390a15050565b6060805f8367ffffffffffffffff81111561089c5761089c6122f4565b6040519080825280602002602001820160405280156108c5578160200160208202803683370190505b5090505f8467ffffffffffffffff8111156108e2576108e26122f4565b60405190808252806020026020018201604052801561090b578160200160208202803683370190505b5090505f5b60ff8116861115610a19575f87878360ff1681811061093157610931612549565b905060200201602081019061094691906120f4565b60085490915060ff90811690821611610a06576001600160a01b0389165f90815260106020908152604080832060ff808616855292529091205485516001600160801b039091169186919085169081106109a2576109a2612549565b6020908102919091018101919091526001600160a01b038a165f90815260108252604080822060ff808616845293529020548451600160801b90910482169185919085169081106109f5576109f5612549565b911515602092830291909101909101525b5080610a11816125a6565b915050610910565b5090969095509350505050565b5f546001600160a01b03163314610a4f5760405162461bcd60e51b81526004016106aa9061255d565b610a585f611b5e565b565b5f546001600160a01b03163314610a835760405162461bcd60e51b81526004016106aa9061255d565b610a8c816118a8565b6005544210610aae57604051630eac48e360e01b815260040160405180910390fd5b610ab784611bad565b600c8260ff1660028110610acd57610acd612549565b6002020180546001600160801b03928316600160801b029216919091179055610af583611bad565b600c8260ff1660028110610b0b57610b0b612549565b6002020180546001600160801b0319166001600160801b0392909216919091179055610b3682611bad565b600c8260ff1660028110610b4c57610b4c612549565b600202016001015f6101000a8154816001600160801b0302191690836001600160801b031602179055505f805f90505b60085460ff90811690821611610bd557600c8160ff1660028110610ba257610ba2612549565b6002020154610bc190600160801b90046001600160801b0316836125c4565b915080610bcd816125a6565b915050610b7c565b50600b819055604080518681526020810186905260ff8416917fddaf243a142670be60c19ff7116b5d8b124717b29bb4cc03cead42161614105b910160405180910390a25050505050565b5f546001600160a01b03163314610c495760405162461bcd60e51b81526004016106aa9061255d565b6001600160a01b038116610c7057604051632b561add60e01b815260040160405180910390fd5b601180546001600160a01b0319166001600160a01b0383169081179091556040517fa7f36ce0102fe26e2c05a5883f82aac2cee294dd4aec8da709ec986aa16e2b7a905f90a250565b688000000000ab143c065c15610cd65763ab143c065f526004601cfd5b30688000000000ab143c065d610ceb836118a8565b604080513060208201526080918101829052600d60a08201526c5665726966794164647265737360981b60c08201523360608201529081018390525f9060e0016040516020818303038152906040528051906020012090505f610da3610d9d836040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c81018290525f90605c01604051602081830303815290604052805190602001209050919050565b84611bc1565b905083421180610dc157506011546001600160a01b03828116911614155b15610ddf5760405163112d49d360e01b815260040160405180910390fd5b600c8560ff1660028110610df557610df5612549565b6002020154600160801b90046001600160801b03161580610e375750600c8560ff1660028110610e2757610e27612549565b60020201546001600160801b0316155b15610e5557604051633c67586360e01b815260040160405180910390fd5b600554421015610e785760405163085de62560e01b815260040160405180910390fd5b600654421115610e9b5760405163ecdd1c2960e01b815260040160405180910390fd5b600b546003546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610ee4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0891906125d7565b1015610f275760405163726da7d560e11b815260040160405180910390fd5b5f80600160ff881660048110610f3f57610f3f612549565b01546001600160a01b031603610f7f57345f03610f6f57604051639e6c689560e01b815260040160405180910390fd5b610f7834611bad565b9050610ff9565b3415610f9e5760405163ac1cb9c960e01b815260040160405180910390fd5b865f03610fbe57604051639e6c689560e01b815260040160405180910390fd5b610fed33308960018a60ff1660048110610fda57610fda612549565b01546001600160a01b0316929190611be5565b610ff687611bad565b90505b335f90815260106020908152604080832060ff8a16845290915290205461102a9082906001600160801b03166125ee565b335f90815260106020908152604080832060ff8b16808552925290912080546001600160801b0319166001600160801b0393909316929092179091556009906002811061107957611079612549565b0154335f90815260106020908152604080832060ff8b1684529091529020546001600160801b031610156110c057604051632fb20d4560e21b815260040160405180910390fd5b5f600c8760ff16600281106110d7576110d7612549565b60020201600101546001600160801b0316111561115557600c8660ff166002811061110457611104612549565b6002020160010154335f90815260106020908152604080832060ff8b1684529091529020546001600160801b03918216911611156111555760405163017976fb60e61b815260040160405180910390fd5b80600c8760ff166002811061116c5761116c612549565b6002020160010160109054906101000a90046001600160801b031661119191906125ee565b600c8760ff16600281106111a7576111a7612549565b6001600291909102919091010180546001600160801b03928316600160801b02908316179055604051908216815260ff87169033907ff763e680fce25a97ffd55d8b705370c98b47b2285f7b3b2900c43606fd4180459060200160405180910390a35050505f688000000000ab143c065d50505050565b60605f8267ffffffffffffffff81111561123a5761123a6122f4565b60405190808252806020026020018201604052801561127357816020015b6112606120aa565b8152602001906001900390816112585790505b5090505f5b60ff811684111561135c575f805f600c88888660ff1681811061129d5761129d612549565b90506020020160208101906112b291906120f4565b60ff16600281106112c5576112c5612549565b60020201546001600160801b031611156113125761130c8888888660ff168181106112f2576112f2612549565b905060200201602081019061130791906120f4565b6118d2565b90925090505b604051806040016040528083815260200182815250848460ff168151811061133c5761133c612549565b602002602001018190525050508080611354906125a6565b915050611278565b50949350505050565b5f546001600160a01b0316331461138e5760405162461bcd60e51b81526004016106aa9061255d565b600281146113af57604051631397ee3560e31b815260040160405180910390fd5b6007546113bc90426125c4565b600654106113dd5760405163eb47c4f360e01b815260040160405180910390fd5b60065460055410611401576040516311af708560e21b815260040160405180910390fd5b600554421061142357604051630eac48e360e01b815260040160405180910390fd5b81815f81811061143557611435612549565b6020029190910135600555508181600181811061145457611454612549565b6020029190910135600655507f57df350cfad05a64accd73700fee8a7febd6d8430e035e45f0599ca62494aa8b82825f8161149157611491612549565b90506020020135838360018181106114ab576114ab612549565b90506020020135604051610873929190918252602082015260400190565b600c81600281106114d8575f80fd5b6002020180546001909101546001600160801b038083169350600160801b9283900481169282821692041684565b5f54600160a01b900460ff161561152f5760405162dc149f60e41b815260040160405180910390fd5b6004851461155057604051633b9b621f60e01b815260040160405180910390fd5b6002831461157157604051631397ee3560e31b815260040160405180910390fd5b5f805460ff60a01b1916600160a01b1781555b60ff81168611156116005786868260ff168181106115a4576115a4612549565b90506020020160208101906115b991906122db565b60018260ff16600481106115cf576115cf612549565b0180546001600160a01b0319166001600160a01b0392909216919091179055806115f8816125a6565b915050611584565b5083835f81811061161357611613612549565b6020029190910135600555508383600181811061163257611632612549565b6020029190910135600655506007829055600160ff821611611662576008805460ff191660ff831617905561167b565b604051633f0e260960e11b815260040160405180910390fd5b6116a68686600381811061169157611691612549565b905060200201602081019061043591906122db565b505050505050565b600181600481106116bd575f80fd5b01546001600160a01b0316905081565b5f546001600160a01b031633146116f65760405162461bcd60e51b81526004016106aa9061255d565b6001600160a01b03811661175b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016106aa565b61176481611b5e565b50565b5f546001600160a01b031633146117905760405162461bcd60e51b81526004016106aa9061255d565b611799816118a8565b8160098260ff16600281106117b0576117b0612549565b015560405182815260ff8216907fefb6532c118ca8bcccd1ad6718d9e3d5f439d4176953ba393f110d80a192182b9060200160405180910390a25050565b60605f8267ffffffffffffffff81111561180a5761180a6122f4565b604051908082528060200260200182016040528015611833578160200160208202803683370190505b5090505f5b60ff811684111561135c576118768686868460ff1681811061185c5761185c612549565b905060200201602081019061187191906120f4565b611c89565b828260ff168151811061188b5761188b612549565b6020908102919091010152806118a0816125a6565b915050611838565b60085460ff908116908216111561176457604051630a26ca2560e31b815260040160405180910390fd5b6001600160a01b0382165f90815260106020908152604080832060ff8516808552925282205482916001600160801b03909116908290600c906002811061191b5761191b612549565b600290810291909101546001600160801b031691508190600c9060ff881690811061194857611948612549565b6002020160010160109054906101000a90046001600160801b03166001600160801b031611156119f7575f61197d8787611c89565b905064e8d4a5100081600c8860ff166002811061199c5761199c612549565b60020201546119bb9190600160801b90046001600160801b031661260d565b6119c59190612638565b94505f64e8d4a510006119d8838561260d565b6119e29190612638565b90506119ee818561264b565b94505050611a4f565b80600c8660ff1660028110611a0e57611a0e612549565b6002020154611a2d90600160801b90046001600160801b03168461260d565b611a379190612638565b935083158015611a4657505f82115b15611a4f578192505b50509250929050565b5f60405163a9059cbb60e01b81526001600160a01b038416600482015282602482015260205f6044835f895af191505080601f3d1160015f511416151615611aa25750823b153d17155b80611ae15760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064016106aa565b50505050565b5f805f805f85875af1905080611b355760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b60448201526064016106aa565b505050565b611b43816118a8565b611b35838360018460ff16600481106105c7576105c7612549565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f600160801b8210611bbd575f80fd5b5090565b5f805f611bce8585611d6d565b91509150611bdb81611dd8565b5090505b92915050565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af191505080601f3d1160015f511416151615611c3e5750833b153d17155b80611c825760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064016106aa565b5050505050565b6008545f9060ff9081169083161115611ca357505f611bdf565b5f600c8360ff1660028110611cba57611cba612549565b6002020160010160109054906101000a90046001600160801b03166001600160801b03161115611d6657600c8260ff1660028110611cfa57611cfa612549565b60020201600101546001600160a01b0384165f90815260106020908152604080832060ff87168452909152902054600160801b9091046001600160801b0390811691611d4c911664e8d4a5100061265e565b611d569190612687565b6001600160801b03169050611bdf565b505f611bdf565b5f808251604103611da1576020830151604084015160608501515f1a611d9587828585611f8d565b94509450505050611dd1565b8251604003611dca5760208301516040840151611dbf868383612072565b935093505050611dd1565b505f905060025b9250929050565b5f816004811115611deb57611deb6126b4565b03611df35750565b6001816004811115611e0757611e076126b4565b03611e545760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016106aa565b6002816004811115611e6857611e686126b4565b03611eb55760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016106aa565b6003816004811115611ec957611ec96126b4565b03611f215760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016106aa565b6004816004811115611f3557611f356126b4565b036117645760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016106aa565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611fc257505f90506003612069565b8460ff16601b14158015611fda57508460ff16601c14155b15611fea57505f90506004612069565b604080515f8082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561203b573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116612063575f60019250925050612069565b91505f90505b94509492505050565b5f806001600160ff1b0383168161208e60ff86901c601b6125c4565b905061209c87828885611f8d565b935093505050935093915050565b60405180604001604052806002906020820280368337509192915050565b5f602082840312156120d8575f80fd5b5035919050565b803560ff811681146120ef575f80fd5b919050565b5f60208284031215612104575f80fd5b61210d826120df565b9392505050565b5f805f60608486031215612126575f80fd5b505081359360208301359350604090920135919050565b80356001600160a01b03811681146120ef575f80fd5b5f8060408385031215612164575f80fd5b61216d8361213d565b946020939093013593505050565b5f8083601f84011261218b575f80fd5b50813567ffffffffffffffff8111156121a2575f80fd5b6020830191508360208260051b8501011115611dd1575f80fd5b5f805f604084860312156121ce575f80fd5b6121d78461213d565b9250602084013567ffffffffffffffff8111156121f2575f80fd5b6121fe8682870161217b565b9497909650939450505050565b5f8151808452602084019350602083015f5b8281101561223b57815186526020958601959091019060010161221d565b5093949350505050565b604081525f612257604083018561220b565b82810360208401528084518083526020830191506020860192505f5b818110156122935783511515835260209384019390920191600101612273565b50909695505050505050565b5f805f80608085870312156122b2575f80fd5b8435935060208501359250604085013591506122d0606086016120df565b905092959194509250565b5f602082840312156122eb575f80fd5b61210d8261213d565b634e487b7160e01b5f52604160045260245ffd5b5f805f806080858703121561231b575f80fd5b8435935061232b602086016120df565b925060408501359150606085013567ffffffffffffffff81111561234d575f80fd5b8501601f8101871361235d575f80fd5b803567ffffffffffffffff811115612377576123776122f4565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156123a6576123a66122f4565b6040528181528282016020018910156123bd575f80fd5b816020840160208301375f6020838301015280935050505092959194509250565b602080825282518282018190525f918401906040840190835b8181101561243c578351835f5b6002811015612423578251825260209283019290910190600101612404565b50505060209390930192604092909201916001016123f7565b509095945050505050565b5f8060208385031215612458575f80fd5b823567ffffffffffffffff81111561246e575f80fd5b61247a8582860161217b565b90969095509350505050565b5f805f805f806080878903121561249b575f80fd5b863567ffffffffffffffff8111156124b1575f80fd5b6124bd89828a0161217b565b909750955050602087013567ffffffffffffffff8111156124dc575f80fd5b6124e889828a0161217b565b90955093505060408701359150612501606088016120df565b90509295509295509295565b5f806040838503121561251e575f80fd5b8235915061252e602084016120df565b90509250929050565b602081525f61210d602083018461220b565b634e487b7160e01b5f52603260045260245ffd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b5f60ff821660ff81036125bb576125bb612592565b60010192915050565b80820180821115611bdf57611bdf612592565b5f602082840312156125e7575f80fd5b5051919050565b6001600160801b038181168382160190811115611bdf57611bdf612592565b8082028115828204841417611bdf57611bdf612592565b634e487b7160e01b5f52601260045260245ffd5b5f8261264657612646612624565b500490565b81810381811115611bdf57611bdf612592565b6001600160801b03818116838216029081169081811461268057612680612592565b5092915050565b5f6001600160801b0383168061269f5761269f612624565b806001600160801b0384160491505092915050565b634e487b7160e01b5f52602160045260245ffdfea26469706673582212205864efc2ee04fd64cfdbff5bfe2642175d283afd0e057a2a78b8223f1c406b2364736f6c634300081a0033
Deployed Bytecode
0x608060405260043610610147575f3560e01c8063a85adeab116100b3578063dfd2bb551161006d578063dfd2bb55146103c8578063e6fd48bc146103e7578063edf26d9b146103fc578063f2fde38b1461041b578063f93bf8331461043a578063f9cd5c1214610459575f80fd5b8063a85adeab146102d8578063b1ced5e7146102ed578063c8aa65c114610318578063ca463ca41461032b578063caa7f23214610357578063ce3f5e4b14610376575f80fd5b80635b7633d0116101045780635b7633d01461021e578063715018a614610255578063760b31801461026957806376920d081461027e5780638da5cb5b1461029d5780638fa2a9f0146102b9575f80fd5b80630f0b7a2b1461014b5780632374876c1461017d5780632937049e1461019e5780633f138d4b146101bd5780634af3c9b7146101dc57806354070e3914610209575b5f80fd5b348015610156575f80fd5b5061016a6101653660046120c8565b610485565b6040519081526020015b60405180910390f35b348015610188575f80fd5b5061019c6101973660046120f4565b61049b565b005b3480156101a9575f80fd5b5061019c6101b8366004612114565b610681565b3480156101c8575f80fd5b5061019c6101d7366004612153565b61076e565b3480156101e7575f80fd5b506101fb6101f63660046121bc565b61087f565b604051610174929190612245565b348015610214575f80fd5b5061016a60075481565b348015610229575f80fd5b5060115461023d906001600160a01b031681565b6040516001600160a01b039091168152602001610174565b348015610260575f80fd5b5061019c610a26565b348015610274575f80fd5b5061016a600b5481565b348015610289575f80fd5b5061019c61029836600461229f565b610a5a565b3480156102a8575f80fd5b505f546001600160a01b031661023d565b3480156102c4575f80fd5b5061019c6102d33660046122db565b610c20565b3480156102e3575f80fd5b5061016a60065481565b3480156102f8575f80fd5b506008546103069060ff1681565b60405160ff9091168152602001610174565b61019c610326366004612308565b610cb9565b348015610336575f80fd5b5061034a6103453660046121bc565b61121e565b60405161017491906123de565b348015610362575f80fd5b5061019c610371366004612447565b611365565b348015610381575f80fd5b506103956103903660046120c8565b6114c9565b604080516001600160801b0395861681529385166020850152918416918301919091529091166060820152608001610174565b3480156103d3575f80fd5b5061019c6103e2366004612486565b611506565b3480156103f2575f80fd5b5061016a60055481565b348015610407575f80fd5b5061023d6104163660046120c8565b6116ae565b348015610426575f80fd5b5061019c6104353660046122db565b6116cd565b348015610445575f80fd5b5061019c61045436600461250d565b611767565b348015610464575f80fd5b506104786104733660046121bc565b6117ee565b6040516101749190612537565b60098160028110610494575f80fd5b0154905081565b688000000000ab143c065c156104b85763ab143c065f526004601cfd5b30688000000000ab143c065d6104cd816118a8565b60065442116104ef5760405163085de62560e01b815260040160405180910390fd5b335f90815260106020908152604080832060ff851684529091528120546001600160801b03169003610534576040516337191a8560e21b815260040160405180910390fd5b335f90815260106020908152604080832060ff8086168552925290912054600160801b90041615610578576040516302cce53760e21b815260040160405180910390fd5b335f81815260106020908152604080832060ff861684529091528120805460ff60801b1916600160801b1790559081906105b290846118d2565b909250905081156105d9576105d93383600160025b01546001600160a01b03169190611a58565b8015610630575f600160ff8516600481106105f6576105f6612549565b01546001600160a01b031603610615576106103382611ae7565b610630565b610630338260018660ff16600481106105c7576105c7612549565b604080518381526020810183905260ff85169133917f51524c2e5edfedf8b01b29719c661e4fbe27e71734e7cd773dabb7cb712fb3b3910160405180910390a350505f688000000000ab143c065d50565b5f546001600160a01b031633146106b35760405162461bcd60e51b81526004016106aa9061255d565b60405180910390fd5b82156106e3576001546001600160a01b03166106d8576106d33384611ae7565b6106e3565b6106e333845f611b3a565b8115610714576002546001600160a01b0316610708576107033383611ae7565b610714565b61071433836001611b3a565b8015610728576107283382600160026105c7565b60408051848152602081018490529081018290527f5cba002c3841a6704789c1f41f4dab171dc5a8c972c928498c961665cdecf41b9060600160405180910390a1505050565b5f546001600160a01b031633146107975760405162461bcd60e51b81526004016106aa9061255d565b6001546001600160a01b03908116908316036107c6576040516310da472360e01b815260040160405180910390fd5b6002546001600160a01b03908116908316036107f5576040516310da472360e01b815260040160405180910390fd5b6003546001600160a01b03908116908316036108245760405163a8dfadb960e01b815260040160405180910390fd5b6108386001600160a01b0383163383611a58565b604080516001600160a01b0384168152602081018390527f74545154aac348a3eac92596bd1971957ca94795f4e954ec5f613b55fab7812991015b60405180910390a15050565b6060805f8367ffffffffffffffff81111561089c5761089c6122f4565b6040519080825280602002602001820160405280156108c5578160200160208202803683370190505b5090505f8467ffffffffffffffff8111156108e2576108e26122f4565b60405190808252806020026020018201604052801561090b578160200160208202803683370190505b5090505f5b60ff8116861115610a19575f87878360ff1681811061093157610931612549565b905060200201602081019061094691906120f4565b60085490915060ff90811690821611610a06576001600160a01b0389165f90815260106020908152604080832060ff808616855292529091205485516001600160801b039091169186919085169081106109a2576109a2612549565b6020908102919091018101919091526001600160a01b038a165f90815260108252604080822060ff808616845293529020548451600160801b90910482169185919085169081106109f5576109f5612549565b911515602092830291909101909101525b5080610a11816125a6565b915050610910565b5090969095509350505050565b5f546001600160a01b03163314610a4f5760405162461bcd60e51b81526004016106aa9061255d565b610a585f611b5e565b565b5f546001600160a01b03163314610a835760405162461bcd60e51b81526004016106aa9061255d565b610a8c816118a8565b6005544210610aae57604051630eac48e360e01b815260040160405180910390fd5b610ab784611bad565b600c8260ff1660028110610acd57610acd612549565b6002020180546001600160801b03928316600160801b029216919091179055610af583611bad565b600c8260ff1660028110610b0b57610b0b612549565b6002020180546001600160801b0319166001600160801b0392909216919091179055610b3682611bad565b600c8260ff1660028110610b4c57610b4c612549565b600202016001015f6101000a8154816001600160801b0302191690836001600160801b031602179055505f805f90505b60085460ff90811690821611610bd557600c8160ff1660028110610ba257610ba2612549565b6002020154610bc190600160801b90046001600160801b0316836125c4565b915080610bcd816125a6565b915050610b7c565b50600b819055604080518681526020810186905260ff8416917fddaf243a142670be60c19ff7116b5d8b124717b29bb4cc03cead42161614105b910160405180910390a25050505050565b5f546001600160a01b03163314610c495760405162461bcd60e51b81526004016106aa9061255d565b6001600160a01b038116610c7057604051632b561add60e01b815260040160405180910390fd5b601180546001600160a01b0319166001600160a01b0383169081179091556040517fa7f36ce0102fe26e2c05a5883f82aac2cee294dd4aec8da709ec986aa16e2b7a905f90a250565b688000000000ab143c065c15610cd65763ab143c065f526004601cfd5b30688000000000ab143c065d610ceb836118a8565b604080513060208201526080918101829052600d60a08201526c5665726966794164647265737360981b60c08201523360608201529081018390525f9060e0016040516020818303038152906040528051906020012090505f610da3610d9d836040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c81018290525f90605c01604051602081830303815290604052805190602001209050919050565b84611bc1565b905083421180610dc157506011546001600160a01b03828116911614155b15610ddf5760405163112d49d360e01b815260040160405180910390fd5b600c8560ff1660028110610df557610df5612549565b6002020154600160801b90046001600160801b03161580610e375750600c8560ff1660028110610e2757610e27612549565b60020201546001600160801b0316155b15610e5557604051633c67586360e01b815260040160405180910390fd5b600554421015610e785760405163085de62560e01b815260040160405180910390fd5b600654421115610e9b5760405163ecdd1c2960e01b815260040160405180910390fd5b600b546003546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610ee4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0891906125d7565b1015610f275760405163726da7d560e11b815260040160405180910390fd5b5f80600160ff881660048110610f3f57610f3f612549565b01546001600160a01b031603610f7f57345f03610f6f57604051639e6c689560e01b815260040160405180910390fd5b610f7834611bad565b9050610ff9565b3415610f9e5760405163ac1cb9c960e01b815260040160405180910390fd5b865f03610fbe57604051639e6c689560e01b815260040160405180910390fd5b610fed33308960018a60ff1660048110610fda57610fda612549565b01546001600160a01b0316929190611be5565b610ff687611bad565b90505b335f90815260106020908152604080832060ff8a16845290915290205461102a9082906001600160801b03166125ee565b335f90815260106020908152604080832060ff8b16808552925290912080546001600160801b0319166001600160801b0393909316929092179091556009906002811061107957611079612549565b0154335f90815260106020908152604080832060ff8b1684529091529020546001600160801b031610156110c057604051632fb20d4560e21b815260040160405180910390fd5b5f600c8760ff16600281106110d7576110d7612549565b60020201600101546001600160801b0316111561115557600c8660ff166002811061110457611104612549565b6002020160010154335f90815260106020908152604080832060ff8b1684529091529020546001600160801b03918216911611156111555760405163017976fb60e61b815260040160405180910390fd5b80600c8760ff166002811061116c5761116c612549565b6002020160010160109054906101000a90046001600160801b031661119191906125ee565b600c8760ff16600281106111a7576111a7612549565b6001600291909102919091010180546001600160801b03928316600160801b02908316179055604051908216815260ff87169033907ff763e680fce25a97ffd55d8b705370c98b47b2285f7b3b2900c43606fd4180459060200160405180910390a35050505f688000000000ab143c065d50505050565b60605f8267ffffffffffffffff81111561123a5761123a6122f4565b60405190808252806020026020018201604052801561127357816020015b6112606120aa565b8152602001906001900390816112585790505b5090505f5b60ff811684111561135c575f805f600c88888660ff1681811061129d5761129d612549565b90506020020160208101906112b291906120f4565b60ff16600281106112c5576112c5612549565b60020201546001600160801b031611156113125761130c8888888660ff168181106112f2576112f2612549565b905060200201602081019061130791906120f4565b6118d2565b90925090505b604051806040016040528083815260200182815250848460ff168151811061133c5761133c612549565b602002602001018190525050508080611354906125a6565b915050611278565b50949350505050565b5f546001600160a01b0316331461138e5760405162461bcd60e51b81526004016106aa9061255d565b600281146113af57604051631397ee3560e31b815260040160405180910390fd5b6007546113bc90426125c4565b600654106113dd5760405163eb47c4f360e01b815260040160405180910390fd5b60065460055410611401576040516311af708560e21b815260040160405180910390fd5b600554421061142357604051630eac48e360e01b815260040160405180910390fd5b81815f81811061143557611435612549565b6020029190910135600555508181600181811061145457611454612549565b6020029190910135600655507f57df350cfad05a64accd73700fee8a7febd6d8430e035e45f0599ca62494aa8b82825f8161149157611491612549565b90506020020135838360018181106114ab576114ab612549565b90506020020135604051610873929190918252602082015260400190565b600c81600281106114d8575f80fd5b6002020180546001909101546001600160801b038083169350600160801b9283900481169282821692041684565b5f54600160a01b900460ff161561152f5760405162dc149f60e41b815260040160405180910390fd5b6004851461155057604051633b9b621f60e01b815260040160405180910390fd5b6002831461157157604051631397ee3560e31b815260040160405180910390fd5b5f805460ff60a01b1916600160a01b1781555b60ff81168611156116005786868260ff168181106115a4576115a4612549565b90506020020160208101906115b991906122db565b60018260ff16600481106115cf576115cf612549565b0180546001600160a01b0319166001600160a01b0392909216919091179055806115f8816125a6565b915050611584565b5083835f81811061161357611613612549565b6020029190910135600555508383600181811061163257611632612549565b6020029190910135600655506007829055600160ff821611611662576008805460ff191660ff831617905561167b565b604051633f0e260960e11b815260040160405180910390fd5b6116a68686600381811061169157611691612549565b905060200201602081019061043591906122db565b505050505050565b600181600481106116bd575f80fd5b01546001600160a01b0316905081565b5f546001600160a01b031633146116f65760405162461bcd60e51b81526004016106aa9061255d565b6001600160a01b03811661175b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016106aa565b61176481611b5e565b50565b5f546001600160a01b031633146117905760405162461bcd60e51b81526004016106aa9061255d565b611799816118a8565b8160098260ff16600281106117b0576117b0612549565b015560405182815260ff8216907fefb6532c118ca8bcccd1ad6718d9e3d5f439d4176953ba393f110d80a192182b9060200160405180910390a25050565b60605f8267ffffffffffffffff81111561180a5761180a6122f4565b604051908082528060200260200182016040528015611833578160200160208202803683370190505b5090505f5b60ff811684111561135c576118768686868460ff1681811061185c5761185c612549565b905060200201602081019061187191906120f4565b611c89565b828260ff168151811061188b5761188b612549565b6020908102919091010152806118a0816125a6565b915050611838565b60085460ff908116908216111561176457604051630a26ca2560e31b815260040160405180910390fd5b6001600160a01b0382165f90815260106020908152604080832060ff8516808552925282205482916001600160801b03909116908290600c906002811061191b5761191b612549565b600290810291909101546001600160801b031691508190600c9060ff881690811061194857611948612549565b6002020160010160109054906101000a90046001600160801b03166001600160801b031611156119f7575f61197d8787611c89565b905064e8d4a5100081600c8860ff166002811061199c5761199c612549565b60020201546119bb9190600160801b90046001600160801b031661260d565b6119c59190612638565b94505f64e8d4a510006119d8838561260d565b6119e29190612638565b90506119ee818561264b565b94505050611a4f565b80600c8660ff1660028110611a0e57611a0e612549565b6002020154611a2d90600160801b90046001600160801b03168461260d565b611a379190612638565b935083158015611a4657505f82115b15611a4f578192505b50509250929050565b5f60405163a9059cbb60e01b81526001600160a01b038416600482015282602482015260205f6044835f895af191505080601f3d1160015f511416151615611aa25750823b153d17155b80611ae15760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064016106aa565b50505050565b5f805f805f85875af1905080611b355760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b60448201526064016106aa565b505050565b611b43816118a8565b611b35838360018460ff16600481106105c7576105c7612549565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f600160801b8210611bbd575f80fd5b5090565b5f805f611bce8585611d6d565b91509150611bdb81611dd8565b5090505b92915050565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af191505080601f3d1160015f511416151615611c3e5750833b153d17155b80611c825760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064016106aa565b5050505050565b6008545f9060ff9081169083161115611ca357505f611bdf565b5f600c8360ff1660028110611cba57611cba612549565b6002020160010160109054906101000a90046001600160801b03166001600160801b03161115611d6657600c8260ff1660028110611cfa57611cfa612549565b60020201600101546001600160a01b0384165f90815260106020908152604080832060ff87168452909152902054600160801b9091046001600160801b0390811691611d4c911664e8d4a5100061265e565b611d569190612687565b6001600160801b03169050611bdf565b505f611bdf565b5f808251604103611da1576020830151604084015160608501515f1a611d9587828585611f8d565b94509450505050611dd1565b8251604003611dca5760208301516040840151611dbf868383612072565b935093505050611dd1565b505f905060025b9250929050565b5f816004811115611deb57611deb6126b4565b03611df35750565b6001816004811115611e0757611e076126b4565b03611e545760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016106aa565b6002816004811115611e6857611e686126b4565b03611eb55760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016106aa565b6003816004811115611ec957611ec96126b4565b03611f215760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016106aa565b6004816004811115611f3557611f356126b4565b036117645760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b60648201526084016106aa565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611fc257505f90506003612069565b8460ff16601b14158015611fda57508460ff16601c14155b15611fea57505f90506004612069565b604080515f8082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561203b573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116612063575f60019250925050612069565b91505f90505b94509492505050565b5f806001600160ff1b0383168161208e60ff86901c601b6125c4565b905061209c87828885611f8d565b935093505050935093915050565b60405180604001604052806002906020820280368337509192915050565b5f602082840312156120d8575f80fd5b5035919050565b803560ff811681146120ef575f80fd5b919050565b5f60208284031215612104575f80fd5b61210d826120df565b9392505050565b5f805f60608486031215612126575f80fd5b505081359360208301359350604090920135919050565b80356001600160a01b03811681146120ef575f80fd5b5f8060408385031215612164575f80fd5b61216d8361213d565b946020939093013593505050565b5f8083601f84011261218b575f80fd5b50813567ffffffffffffffff8111156121a2575f80fd5b6020830191508360208260051b8501011115611dd1575f80fd5b5f805f604084860312156121ce575f80fd5b6121d78461213d565b9250602084013567ffffffffffffffff8111156121f2575f80fd5b6121fe8682870161217b565b9497909650939450505050565b5f8151808452602084019350602083015f5b8281101561223b57815186526020958601959091019060010161221d565b5093949350505050565b604081525f612257604083018561220b565b82810360208401528084518083526020830191506020860192505f5b818110156122935783511515835260209384019390920191600101612273565b50909695505050505050565b5f805f80608085870312156122b2575f80fd5b8435935060208501359250604085013591506122d0606086016120df565b905092959194509250565b5f602082840312156122eb575f80fd5b61210d8261213d565b634e487b7160e01b5f52604160045260245ffd5b5f805f806080858703121561231b575f80fd5b8435935061232b602086016120df565b925060408501359150606085013567ffffffffffffffff81111561234d575f80fd5b8501601f8101871361235d575f80fd5b803567ffffffffffffffff811115612377576123776122f4565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156123a6576123a66122f4565b6040528181528282016020018910156123bd575f80fd5b816020840160208301375f6020838301015280935050505092959194509250565b602080825282518282018190525f918401906040840190835b8181101561243c578351835f5b6002811015612423578251825260209283019290910190600101612404565b50505060209390930192604092909201916001016123f7565b509095945050505050565b5f8060208385031215612458575f80fd5b823567ffffffffffffffff81111561246e575f80fd5b61247a8582860161217b565b90969095509350505050565b5f805f805f806080878903121561249b575f80fd5b863567ffffffffffffffff8111156124b1575f80fd5b6124bd89828a0161217b565b909750955050602087013567ffffffffffffffff8111156124dc575f80fd5b6124e889828a0161217b565b90955093505060408701359150612501606088016120df565b90509295509295509295565b5f806040838503121561251e575f80fd5b8235915061252e602084016120df565b90509250929050565b602081525f61210d602083018461220b565b634e487b7160e01b5f52603260045260245ffd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b5f52601160045260245ffd5b5f60ff821660ff81036125bb576125bb612592565b60010192915050565b80820180821115611bdf57611bdf612592565b5f602082840312156125e7575f80fd5b5051919050565b6001600160801b038181168382160190811115611bdf57611bdf612592565b8082028115828204841417611bdf57611bdf612592565b634e487b7160e01b5f52601260045260245ffd5b5f8261264657612646612624565b500490565b81810381811115611bdf57611bdf612592565b6001600160801b03818116838216029081169081811461268057612680612592565b5092915050565b5f6001600160801b0383168061269f5761269f612624565b806001600160801b0384160491505092915050565b634e487b7160e01b5f52602160045260245ffdfea26469706673582212205864efc2ee04fd64cfdbff5bfe2642175d283afd0e057a2a78b8223f1c406b2364736f6c634300081a0033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$22,248.84
Net Worth in BNB
Token Allocations
BNB
100.00%
Multichain Portfolio | 32 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| BSC | 100.00% | $616.28 | 36.1021 | $22,248.84 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
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.