Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
BNBMagaStaking
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
error ZeroAddress(string parameter);
error InvalidAmount(string parameter);
error PoolDisabled(uint8 poolId);
error PoolExpired(uint8 poolId);
error ReferralRequirementNotMet(uint8 poolId, uint256 required, uint256 actual);
error PoolCapExceeded(uint8 poolId, uint256 cap);
error PoolAccountingUnderflow(uint8 poolId);
error NotPresale();
error ReferralOracleUnset();
error NotPositionOwner();
error PositionWithdrawn(uint256 positionId);
error CompoundDisabled(uint8 poolId);
error HardLockActive(uint256 positionId);
error RewardsUnavailable();
error MissingPresaleTokens();
error AttestationFailed();
error PositionDoesNotExist(uint256 positionId);
error UseDrainRewards();
/// Referral count source (presale/oracle/backend).
interface IReferralOracle {
function referralCount(address user) external view returns (uint256);
}
/// Used to push a fresh global referral count before staking.
interface IReferralAttestor {
function updateReferralAttestation(
address referrer,
uint256 attestedGlobalCount,
uint256 deadline,
uint256 syncFee,
bytes calldata sig
) external;
}
/**
* @title BNBMAGA Staking
* @notice Single-token staking with configurable pools (locks, referrals, dynamic APR).
* @dev Rewards are funded by the owner and accrue per second.
*/
contract BNBMagaStaking is Ownable, Pausable, ReentrancyGuard {
using SafeERC20 for IERC20;
IERC20 public immutable stakingToken;
address public immutable rewardTreasury;
/// Presale contract that can create positions for buyers (optional).
address public presaleContract;
/// External referral count source (optional).
address public referralOracle;
/// If true, allows early withdraw from hard-locked positions (emergency switch).
bool public emergencyUnlockAll;
// ----------- Limits -----------
uint32 public constant MAX_APR_BPS = 1_000_000; // 10000% max APR (base + boosts)
uint32 public constant MAX_PENALTY_BPS = 10_000; // 100% max penalty
// ----------- Pool / Position -----------
struct Pool {
uint256 lockDuration;
uint32 aprBps;
uint32 earlyPenaltyBps;
bool enabled;
bool hardLock;
}
struct Position {
address owner;
uint256 amount; // principal
uint256 start;
uint256 lastClaim; // last reward update
uint256 unlockAt;
uint32 aprBps; // APR snapshot (base + boosts)
uint8 poolId; // pool identifier
bool withdrawn;
bool hardLock; // hard lock was enabled on pool at stake time
}
mapping(uint8 => Pool) public pools; // poolId => config
mapping(uint256 => Position) public positions; // positionId => position
mapping(address => uint256[]) public userPositions;
uint256 public totalStaked; // sum of principals
uint256 public nextPositionId = 1;
// --- Pool capacity controls ---
mapping(uint8 => uint256) public poolPrincipal; // live principal in pool
mapping(uint8 => uint256) public poolMaxPrincipal;
// --- Referral gating (min refs needed to join) ---
mapping(uint8 => uint256) public poolMinReferrals;
// --- Referral APR boosts (optional, per pool) ---
mapping(uint8 => bool) public poolReferralBoostEnabled;
mapping(uint8 => uint32) public poolBoostBpsPerTier;
mapping(uint8 => uint256) public poolBoostTierSize;
mapping(uint8 => uint32) public poolMaxBoostBps;
// --- Pool expiry (per pool) ---
// deadline == 0: no expiry.
// deadline > 0 and block.timestamp > deadline:
// - no new deposits/compounds
// - if stopAccrual == true, rewards stop accruing after deadline
mapping(uint8 => uint256) public poolStakeDeadline; // unix timestamp; 0 = no deadline
mapping(uint8 => bool) public poolExpireStopsAccrual; // default false
// --- Compound toggle (opt-in, per pool) ---
mapping(uint8 => bool) public poolCompoundEnabled; // default false (disabled)
// --- Dynamic APR (optional, per pool) ---
mapping(uint8 => bool) public poolDynamicAprEnabled; // off by default
mapping(uint8 => uint32) public poolDynamicBpsPer1e18; // extra bps per 1e18 staked (this position)
mapping(uint8 => uint32) public poolDynamicMaxBoostBps; // cap on dynamic boost (bps)
mapping(uint8 => bool) public poolDynamicRepriceOnCompound; // if true, update APR snapshot on compound()
/// @dev If >0, enables step mode: +1 bp for each `tokensPerBp1e18` tokens (1e18 units) in THIS position.
mapping(uint8 => uint256) public poolDynamicTokensPerBp1e18;
// ----------- Events -----------
event PoolSet(
uint8 indexed poolId,
uint256 lockDuration,
uint32 aprBps,
uint32 earlyPenaltyBps,
bool enabled,
bool hardLock
);
event PoolCapSet(uint8 indexed poolId, uint256 maxPrincipal);
event PoolMinReferralsSet(uint8 indexed poolId, uint256 minReferrals);
event PoolBoostSet(uint8 indexed poolId, bool enabled, uint32 boostBpsPerTier, uint256 tierSize);
event PoolMaxBoostSet(uint8 indexed poolId, uint32 maxBoostBps);
event PoolExpirySet(uint8 indexed poolId, uint256 deadline, bool stopAccrual);
event PoolCompoundSet(uint8 indexed poolId, bool enabled);
event PoolDynamicAprSet(
uint8 indexed poolId,
bool enabled,
uint32 bpsPer1e18,
uint32 maxBoostBps,
bool repriceOnCompound
);
event PoolDynamicAprStepsSet(
uint8 indexed poolId,
bool enabled,
uint256 tokensPerBp1e18,
uint32 maxBoostBps,
bool repriceOnCompound
);
event PresaleContractSet(address indexed presale);
event ReferralOracleSet(address indexed oracle);
event EmergencyUnlockAllSet(bool enabled);
event RewardsFunded(address indexed from, uint256 amount);
event DrainedRewards(address indexed to, uint256 amount);
event RescuedTokens(address indexed token, address indexed to, uint256 amount);
event Staked(address indexed user, uint256 indexed positionId, uint8 poolId, uint256 amount);
event Claimed(address indexed user, uint256 indexed positionId, uint256 reward);
event ClaimedBatch(address indexed user, uint256 totalReward, uint256 count);
event EarlyClaimPenalty(address indexed user, uint256 indexed positionId, uint256 penalty);
event EarlyClaimPenaltyBatch(address indexed user, uint256 totalPenalty, uint256 count);
event Compounded(address indexed user, uint256 indexed positionId, uint256 rewardAdded, uint256 newPrincipal);
event Withdrawn(address indexed user, uint256 indexed positionId, uint256 principal, uint256 reward, uint256 penalty);
event EmergencyWithdraw(address indexed user, uint256 indexed positionId, uint256 principalForfeitedReward);
event PoolPaused(uint8 indexed poolId);
event PoolUnpaused(uint8 indexed poolId);
event PoolDeleted(uint8 indexed poolId);
// ----------- Init -----------
constructor(address _token, address _rewardTreasury) Ownable(msg.sender) {
if (_token == address(0)) revert ZeroAddress("token");
if (_rewardTreasury == address(0)) revert ZeroAddress("rewardTreasury");
stakingToken = IERC20(_token);
rewardTreasury = _rewardTreasury;
}
// ----------- Internal guardrails -----------
function _nonZero(address value, string memory tag) private pure {
if (value == address(0)) revert ZeroAddress(tag);
}
function _positive(uint256 value, string memory tag) private pure {
if (value == 0) revert InvalidAmount(tag);
}
function _fetchActivePool(uint8 poolId) private view returns (Pool memory pool) {
pool = pools[poolId];
if (!pool.enabled) revert PoolDisabled(poolId);
}
function _ensurePoolAcceptsPrincipal(uint8 poolId) private view {
if (!_poolAcceptsNewPrincipal(poolId)) revert PoolExpired(poolId);
}
function _enforceReferralGate(address user, uint8 poolId) private view {
uint256 minRefs = poolMinReferrals[poolId];
if (minRefs == 0) return;
uint256 refs = _refCount(user);
if (refs < minRefs) revert ReferralRequirementNotMet(poolId, minRefs, refs);
}
function _createPosition(address owner_, uint256 amount, uint8 poolId, Pool memory pool)
private
returns (uint256 positionId)
{
positionId = nextPositionId++;
uint256 nowTs = block.timestamp;
uint32 aprSnapshot = _effectiveAprForWithAmount(owner_, poolId, amount);
positions[positionId] = Position({
owner: owner_,
amount: amount,
start: nowTs,
lastClaim: nowTs,
unlockAt: pool.lockDuration == 0 ? 0 : (nowTs + pool.lockDuration),
aprBps: aprSnapshot,
poolId: poolId,
withdrawn: false,
hardLock: pool.hardLock
});
userPositions[owner_].push(positionId);
totalStaked += amount;
emit Staked(owner_, positionId, poolId, amount);
}
// ----------- Admin: pool/core config -----------
function setPool(
uint8 poolId,
uint256 lockDuration,
uint32 aprBps,
uint32 earlyPenaltyBps,
bool enabled,
bool hardLock
) external onlyOwner {
require(aprBps <= MAX_APR_BPS, "apr too high");
require(earlyPenaltyBps <= MAX_PENALTY_BPS, "penalty too high");
pools[poolId] = Pool({
lockDuration: lockDuration,
aprBps: aprBps,
earlyPenaltyBps: earlyPenaltyBps,
enabled: enabled,
hardLock: hardLock
});
emit PoolSet(poolId, lockDuration, aprBps, earlyPenaltyBps, enabled, hardLock);
}
function pausePool(uint8 poolId) external onlyOwner {
pools[poolId].enabled = false;
emit PoolPaused(poolId);
}
function unpausePool(uint8 poolId) external onlyOwner {
pools[poolId].enabled = true;
emit PoolUnpaused(poolId);
}
function deletePool(uint8 poolId) external onlyOwner {
require(poolPrincipal[poolId] == 0, "pool has principal");
// Clear core pool config
delete pools[poolId];
// Clear aux config
delete poolMaxPrincipal[poolId];
delete poolMinReferrals[poolId];
delete poolReferralBoostEnabled[poolId];
delete poolBoostBpsPerTier[poolId];
delete poolBoostTierSize[poolId];
delete poolMaxBoostBps[poolId];
delete poolCompoundEnabled[poolId];
// Clear expiry config
delete poolStakeDeadline[poolId];
delete poolExpireStopsAccrual[poolId];
// Clear dynamic APR config
delete poolDynamicAprEnabled[poolId];
delete poolDynamicBpsPer1e18[poolId];
delete poolDynamicMaxBoostBps[poolId];
delete poolDynamicRepriceOnCompound[poolId];
delete poolDynamicTokensPerBp1e18[poolId];
emit PoolDeleted(poolId);
}
function setPoolCap(uint8 poolId, uint256 maxPrincipal) external onlyOwner {
if (maxPrincipal != 0 && maxPrincipal < poolPrincipal[poolId]) {
revert InvalidAmount("poolCap");
}
poolMaxPrincipal[poolId] = maxPrincipal;
emit PoolCapSet(poolId, maxPrincipal);
}
function setMinReferrals(uint8 poolId, uint256 minRefs) external onlyOwner {
poolMinReferrals[poolId] = minRefs;
emit PoolMinReferralsSet(poolId, minRefs);
}
function setReferralBoostConfig(
uint8 poolId,
bool enabled,
uint32 boostBpsPerTier,
uint256 tierSize
) external onlyOwner {
poolReferralBoostEnabled[poolId] = enabled;
poolBoostBpsPerTier[poolId] = boostBpsPerTier;
poolBoostTierSize[poolId] = tierSize;
emit PoolBoostSet(poolId, enabled, boostBpsPerTier, tierSize);
}
function setPoolMaxBoostBps(uint8 poolId, uint32 maxBoostBps) external onlyOwner {
poolMaxBoostBps[poolId] = maxBoostBps;
emit PoolMaxBoostSet(poolId, maxBoostBps);
}
function setPoolCompoundEnabled(uint8 poolId, bool enabled) external onlyOwner {
poolCompoundEnabled[poolId] = enabled;
emit PoolCompoundSet(poolId, enabled);
}
function setPoolDynamicAprConfig(
uint8 poolId,
bool enabled,
uint32 bpsPer1e18,
uint32 maxBoostBps,
bool repriceOnCompound
) external onlyOwner {
poolDynamicAprEnabled[poolId] = enabled;
poolDynamicBpsPer1e18[poolId] = bpsPer1e18;
poolDynamicMaxBoostBps[poolId] = maxBoostBps;
poolDynamicRepriceOnCompound[poolId] = repriceOnCompound;
emit PoolDynamicAprSet(poolId, enabled, bpsPer1e18, maxBoostBps, repriceOnCompound);
}
/// @notice Dynamic APR step mode: +1 bp per `tokensPerBp1e18` tokens in this position.
function setPoolDynamicAprSteps(
uint8 poolId,
bool enabled,
uint256 tokensPerBp1e18, // tokens (1e18 units) per +1 bp;
uint32 maxBoostBps,
bool repriceOnCompound
) external onlyOwner {
poolDynamicAprEnabled[poolId] = enabled;
poolDynamicTokensPerBp1e18[poolId] = tokensPerBp1e18;
poolDynamicMaxBoostBps[poolId] = maxBoostBps;
poolDynamicRepriceOnCompound[poolId] = repriceOnCompound;
emit PoolDynamicAprStepsSet(poolId, enabled, tokensPerBp1e18, maxBoostBps, repriceOnCompound);
}
function setPresaleContract(address presale) external onlyOwner {
presaleContract = presale;
emit PresaleContractSet(presale);
}
function setReferralOracle(address oracle) external onlyOwner {
_nonZero(oracle, "oracle");
referralOracle = oracle;
emit ReferralOracleSet(oracle);
}
function clearReferralOracle() external onlyOwner {
referralOracle = address(0);
emit ReferralOracleSet(address(0));
}
function setEmergencyUnlockAll(bool enabled) external onlyOwner {
emergencyUnlockAll = enabled;
emit EmergencyUnlockAllSet(enabled);
}
/// @notice Pool expiry (opt-in)
function setPoolExpiry(
uint8 poolId,
uint256 deadline,
bool stopAccrual
) external onlyOwner {
poolStakeDeadline[poolId] = deadline;
poolExpireStopsAccrual[poolId] = stopAccrual;
emit PoolExpirySet(poolId, deadline, stopAccrual);
}
function pause() external onlyOwner { _pause(); }
function unpause() external onlyOwner { _unpause(); }
// ----------- Funding / Rescue -----------
function fundRewards(uint256 amount) external onlyOwner {
_positive(amount, "amount");
stakingToken.safeTransferFrom(msg.sender, address(this), amount);
emit RewardsFunded(msg.sender, amount);
}
/**
* @dev Withdraw surplus rewards (balance above totalStaked) to rewardTreasury.
* Can only be called while the contract is paused.
*/
function drainRewards(uint256 amount) external onlyOwner nonReentrant whenPaused {
_positive(amount, "amount");
uint256 avail = rewardAvailable();
if (avail < amount) revert RewardsUnavailable();
stakingToken.safeTransfer(rewardTreasury, amount);
emit DrainedRewards(rewardTreasury, amount);
}
/**
* @dev Rescue non-staking tokens to rewardTreasury while paused.
* Staking token is handled via drainRewards().
*/
function rescueTokens(address token, uint256 amount) external onlyOwner nonReentrant whenPaused {
if (token == address(stakingToken)) revert UseDrainRewards();
_positive(amount, "amount");
IERC20(token).safeTransfer(rewardTreasury, amount);
emit RescuedTokens(token, rewardTreasury, amount);
}
// ----------- Views -----------
function rewardAvailable() public view returns (uint256) {
uint256 bal = stakingToken.balanceOf(address(this));
return bal > totalStaked ? bal - totalStaked : 0;
}
function positionsOf(address user) external view returns (uint256[] memory) {
return userPositions[user];
}
function getPoolExpiry(uint8 poolId) external view returns (uint256 deadline, bool stopAccrual) {
return (poolStakeDeadline[poolId], poolExpireStopsAccrual[poolId]);
}
function getPoolDynamicConfig(uint8 poolId)
external
view
returns (
bool enabled,
uint32 bpsPer1e18,
uint256 tokensPerBp1e18,
uint32 maxBoostBps,
bool repriceOnCompound
)
{
enabled = poolDynamicAprEnabled[poolId];
bpsPer1e18 = poolDynamicBpsPer1e18[poolId];
tokensPerBp1e18 = poolDynamicTokensPerBp1e18[poolId];
maxBoostBps = poolDynamicMaxBoostBps[poolId];
repriceOnCompound = poolDynamicRepriceOnCompound[poolId];
}
function _accrued(Position memory p, uint256 toTs) internal view returns (uint256) {
if (p.withdrawn || toTs <= p.lastClaim) return 0;
// For locked positions, don't accrue past unlock time.
uint256 capTs = p.unlockAt == 0 ? toTs : (toTs < p.unlockAt ? toTs : p.unlockAt);
// Optionally stop accrual at pool expiry.
if (poolExpireStopsAccrual[p.poolId]) {
uint256 d = poolStakeDeadline[p.poolId];
if (d != 0 && capTs > d) capTs = d;
}
if (capTs <= p.lastClaim) return 0;
uint256 dt = capTs - p.lastClaim;
return (p.amount * uint256(p.aprBps) * dt) / (10000 * 365 days);
}
function pending(uint256 positionId) public view returns (uint256) {
Position memory p = positions[positionId];
if (p.owner == address(0)) revert PositionDoesNotExist(positionId);
return _accrued(p, block.timestamp);
}
function getPoolInfo(uint8 poolId)
external
view
returns (
uint256 lockDuration,
uint32 aprBps,
uint32 earlyPenaltyBps,
bool enabled,
bool hardLock,
uint256 currentPrincipal,
uint256 maxPrincipal
)
{
Pool memory pool = pools[poolId];
lockDuration = pool.lockDuration;
aprBps = pool.aprBps;
earlyPenaltyBps = pool.earlyPenaltyBps;
enabled = pool.enabled;
hardLock = pool.hardLock;
currentPrincipal = poolPrincipal[poolId];
maxPrincipal = poolMaxPrincipal[poolId];
}
function getPoolGates(uint8 poolId) external view returns (uint256 minReferrals) {
return poolMinReferrals[poolId];
}
function getUserReferralCount(address user) external view returns (uint256) {
return _refCount(user);
}
function getPoolBoostCaps(uint8 poolId) external view returns (uint32 perPoolBoostCapBps) {
return poolMaxBoostBps[poolId];
}
function previewAprFor(address user, uint8 poolId)
external
view
returns (uint32 baseAprBps, uint32 boostAprBps, uint32 finalAprBps)
{
Pool memory pool = pools[poolId];
baseAprBps = pool.aprBps;
boostAprBps = _boostBps(user, poolId);
uint256 combined = uint256(baseAprBps) + uint256(boostAprBps);
if (combined > MAX_APR_BPS) combined = MAX_APR_BPS;
finalAprBps = uint32(combined);
}
function previewAprForAmount(address user, uint8 poolId, uint256 amount)
external
view
returns (uint32 baseAprBps, uint32 referralBoostBps, uint32 dynamicBoostBps, uint32 finalAprBps)
{
Pool memory pool = pools[poolId];
baseAprBps = pool.aprBps;
referralBoostBps = _boostBps(user, poolId);
dynamicBoostBps = _dynamicBoostBps(amount, poolId);
uint256 sum = uint256(baseAprBps) + uint256(referralBoostBps) + uint256(dynamicBoostBps);
if (sum > MAX_APR_BPS) sum = MAX_APR_BPS;
finalAprBps = uint32(sum);
}
// ----------- Internal helpers -----------
function _refCount(address user) internal view returns (uint256) {
if (referralOracle == address(0)) return 0;
return IReferralOracle(referralOracle).referralCount(user);
}
function _boostBps(address user, uint8 poolId) internal view returns (uint32) {
if (!poolReferralBoostEnabled[poolId]) return 0;
uint256 tierSize = poolBoostTierSize[poolId];
if (tierSize == 0) return 0;
uint256 refs = _refCount(user);
uint256 tiers = refs / tierSize;
uint256 boost = tiers * poolBoostBpsPerTier[poolId];
uint32 perPoolCap = poolMaxBoostBps[poolId];
if (perPoolCap > 0 && boost > perPoolCap) boost = perPoolCap;
if (boost > type(uint32).max) boost = type(uint32).max;
return uint32(boost);
}
/// @dev Dynamic APR boost for this position.
/// Uses step mode if tokensPerBp1e18 > 0, otherwise linear.
function _dynamicBoostBps(uint256 amount, uint8 poolId) internal view returns (uint32) {
if (!poolDynamicAprEnabled[poolId] || amount == 0) return 0;
uint32 cap = poolDynamicMaxBoostBps[poolId];
uint256 tokensPerBp = poolDynamicTokensPerBp1e18[poolId];
uint256 boost;
if (tokensPerBp > 0) {
// Step mode
boost = amount / tokensPerBp; // integer number of +1 bp steps
} else {
// Linear mode (existing behavior)
uint256 per = uint256(poolDynamicBpsPer1e18[poolId]); // bps per 1 token (1e18)
boost = (amount / 1e18) * per;
}
if (cap > 0 && boost > cap) boost = cap;
if (boost > type(uint32).max) boost = type(uint32).max;
return uint32(boost);
}
function _effectiveAprForWithAmount(address user, uint8 poolId, uint256 amount)
internal
view
returns (uint32)
{
Pool memory pool = pools[poolId];
uint256 sum =
uint256(pool.aprBps) +
uint256(_boostBps(user, poolId)) +
uint256(_dynamicBoostBps(amount, poolId));
if (sum > MAX_APR_BPS) sum = MAX_APR_BPS;
return uint32(sum);
}
function _effectiveAprFor(address user, uint8 poolId) internal view returns (uint32) {
Pool memory pool = pools[poolId];
uint32 base = pool.aprBps;
uint32 boost = _boostBps(user, poolId);
uint256 sum = uint256(base) + uint256(boost);
if (sum > MAX_APR_BPS) sum = MAX_APR_BPS;
return uint32(sum);
}
function _enforceAndBumpPoolPrincipal(uint8 poolId, uint256 delta) internal {
uint256 cap = poolMaxPrincipal[poolId];
if (cap != 0) {
if (poolPrincipal[poolId] + delta > cap) revert PoolCapExceeded(poolId, cap);
}
poolPrincipal[poolId] += delta;
}
function _decreasePoolPrincipal(uint8 poolId, uint256 delta) internal {
uint256 cur = poolPrincipal[poolId];
if (cur < delta) revert PoolAccountingUnderflow(poolId);
poolPrincipal[poolId] = cur - delta;
}
function _poolAcceptsNewPrincipal(uint8 poolId) internal view returns (bool) {
uint256 d = poolStakeDeadline[poolId];
return d == 0 || block.timestamp <= d; // inclusive
}
// ----------- Core: Stake / Claim / Withdraw -----------
function stake(uint256 amount, uint8 poolId)
public
nonReentrant
whenNotPaused
returns (uint256 positionId)
{
_positive(amount, "amount");
Pool memory pool = _fetchActivePool(poolId);
_ensurePoolAcceptsPrincipal(poolId);
_enforceReferralGate(msg.sender, poolId);
_enforceAndBumpPoolPrincipal(poolId, amount);
stakingToken.safeTransferFrom(msg.sender, address(this), amount);
positionId = _createPosition(msg.sender, amount, poolId, pool);
}
function stakeWithPermit(
uint256 amount,
uint8 poolId,
uint256 deadline,
uint8 v, bytes32 r, bytes32 s
) external returns (uint256 positionId) {
IERC20Permit(address(stakingToken)).permit(
msg.sender,
address(this),
amount,
deadline,
v, r, s
);
return stake(amount, poolId);
}
function stakeWithPermitAndAttest(
uint256 amount,
uint8 poolId,
uint256 attestedGlobalCount,
uint256 attestDeadline,
uint256 syncFee,
bytes calldata attestSig,
uint256 permitDeadline,
uint8 v, bytes32 r, bytes32 s
) external whenNotPaused returns (uint256 positionId) {
_positive(amount, "amount");
if (referralOracle == address(0)) revert ReferralOracleUnset();
IReferralAttestor(referralOracle).updateReferralAttestation(
msg.sender,
attestedGlobalCount,
attestDeadline,
syncFee,
attestSig
);
IERC20Permit(address(stakingToken)).permit(
msg.sender,
address(this),
amount,
permitDeadline,
v, r, s
);
positionId = stake(amount, poolId);
}
function stakeWithPermitAndTryAttest(
uint256 amount,
uint8 poolId,
uint256 attestedGlobalCount,
uint256 attestDeadline,
uint256 syncFee,
bytes calldata attestSig,
uint256 permitDeadline,
uint8 v, bytes32 r, bytes32 s,
bool requireAttest
) external payable whenNotPaused returns (uint256 positionId) {
if (referralOracle != address(0)) {
try IReferralAttestor(referralOracle).updateReferralAttestation(
msg.sender, attestedGlobalCount, attestDeadline, syncFee, attestSig
) {
} catch {
if (requireAttest) revert AttestationFailed();
}
}
IERC20Permit(address(stakingToken)).permit(
msg.sender, address(this), amount, permitDeadline, v, r, s
);
positionId = stake(amount, poolId);
}
function stakeAndAttest(
uint256 amount,
uint8 poolId,
uint256 attestedGlobalCount,
uint256 attestDeadline,
uint256 syncFee,
bytes calldata attestSig
) external whenNotPaused returns (uint256 positionId) {
_positive(amount, "amount");
if (referralOracle == address(0)) revert ReferralOracleUnset();
IReferralAttestor(referralOracle).updateReferralAttestation(
msg.sender,
attestedGlobalCount,
attestDeadline,
syncFee,
attestSig
);
positionId = stake(amount, poolId);
}
function onPresaleReceive(address user, uint256 amount, uint8 poolId)
external
nonReentrant
whenNotPaused
returns (uint256 positionId)
{
if (msg.sender != presaleContract) revert NotPresale();
_nonZero(user, "user");
_positive(amount, "amount");
Pool memory pool = _fetchActivePool(poolId);
_ensurePoolAcceptsPrincipal(poolId);
_enforceReferralGate(user, poolId);
_enforceAndBumpPoolPrincipal(poolId, amount);
// Double-check that the presale tokens are here.
uint256 bal = stakingToken.balanceOf(address(this));
if (bal < totalStaked + amount) revert MissingPresaleTokens();
positionId = _createPosition(user, amount, poolId, pool);
}
function claim(uint256 positionId)
public
nonReentrant
whenNotPaused
returns (uint256 reward)
{
Position storage p = positions[positionId];
if (p.owner != msg.sender) revert NotPositionOwner();
if (p.withdrawn) revert PositionWithdrawn(positionId);
Pool memory pool = pools[p.poolId];
reward = _accrued(p, block.timestamp);
p.lastClaim = block.timestamp;
if (reward > 0) {
uint256 penalty = 0;
bool early = (p.unlockAt != 0 && block.timestamp < p.unlockAt);
if (!p.hardLock && early && pool.earlyPenaltyBps > 0) {
uint256 calc = (reward * uint256(pool.earlyPenaltyBps)) / 10000;
if (calc > reward) calc = reward;
penalty = calc;
reward = reward - penalty;
emit EarlyClaimPenalty(msg.sender, positionId, penalty);
}
if (rewardAvailable() < reward) revert RewardsUnavailable();
stakingToken.safeTransfer(msg.sender, reward);
emit Claimed(msg.sender, positionId, reward);
}
}
function claimMany(uint256[] calldata positionIds)
external
nonReentrant
whenNotPaused
returns (uint256 totalReward)
{
uint256 len = positionIds.length;
uint256 totalPenalty = 0;
for (uint256 i = 0; i < len; i++) {
uint256 id = positionIds[i];
Position storage p = positions[id];
if (p.owner != msg.sender) revert NotPositionOwner();
if (p.withdrawn) revert PositionWithdrawn(id);
uint256 r = _accrued(p, block.timestamp);
if (r > 0) {
Pool memory pool = pools[p.poolId];
bool early = (p.unlockAt != 0 && block.timestamp < p.unlockAt);
if (!p.hardLock && early && pool.earlyPenaltyBps > 0) {
uint256 penalty = (r * uint256(pool.earlyPenaltyBps)) / 10000;
if (penalty > r) penalty = r;
r -= penalty;
totalPenalty += penalty;
}
totalReward += r;
}
p.lastClaim = block.timestamp;
}
if (totalReward > 0) {
if (rewardAvailable() < totalReward) revert RewardsUnavailable();
stakingToken.safeTransfer(msg.sender, totalReward);
}
if (totalPenalty > 0) {
emit EarlyClaimPenaltyBatch(msg.sender, totalPenalty, len);
}
emit ClaimedBatch(msg.sender, totalReward, len);
}
function compound(uint256 positionId)
external
nonReentrant
whenNotPaused
returns (uint256 rewardAdded, uint256 newPrincipal)
{
Position storage p = positions[positionId];
if (p.owner != msg.sender) revert NotPositionOwner();
if (p.withdrawn) revert PositionWithdrawn(positionId);
if (!poolCompoundEnabled[p.poolId]) revert CompoundDisabled(p.poolId);
_ensurePoolAcceptsPrincipal(p.poolId);
uint256 accruedReward = _accrued(p, block.timestamp);
p.lastClaim = block.timestamp;
if (accruedReward > 0) {
Pool memory pool = pools[p.poolId];
bool early = (p.unlockAt != 0 && block.timestamp < p.unlockAt);
if (!p.hardLock && early && pool.earlyPenaltyBps > 0) {
uint256 penalty = (accruedReward * uint256(pool.earlyPenaltyBps)) / 10000;
if (penalty > accruedReward) penalty = accruedReward;
accruedReward -= penalty;
emit EarlyClaimPenalty(msg.sender, positionId, penalty);
}
if (rewardAvailable() < accruedReward) revert RewardsUnavailable();
_enforceAndBumpPoolPrincipal(p.poolId, accruedReward);
rewardAdded = accruedReward;
p.amount += rewardAdded;
totalStaked += rewardAdded; // reward becomes principal
newPrincipal = p.amount;
if (poolDynamicRepriceOnCompound[p.poolId]) {
p.aprBps = _effectiveAprForWithAmount(msg.sender, p.poolId, p.amount);
}
emit Compounded(msg.sender, positionId, rewardAdded, newPrincipal);
} else {
newPrincipal = p.amount;
}
}
function withdraw(uint256 positionId) external nonReentrant whenNotPaused {
Position storage p = positions[positionId];
if (p.owner != msg.sender) revert NotPositionOwner();
if (p.withdrawn) revert PositionWithdrawn(positionId);
Pool memory pool = pools[p.poolId];
uint256 reward = _accrued(p, block.timestamp);
uint256 penalty = 0;
bool early = (p.unlockAt != 0 && block.timestamp < p.unlockAt);
if (p.hardLock && early && !emergencyUnlockAll) revert HardLockActive(positionId);
if (!p.hardLock && early && pool.earlyPenaltyBps > 0 && reward > 0) {
uint256 calc = (reward * uint256(pool.earlyPenaltyBps)) / 10000;
if (calc > reward) calc = reward;
penalty = calc;
reward = reward - penalty;
}
p.withdrawn = true;
totalStaked -= p.amount;
_decreasePoolPrincipal(p.poolId, p.amount);
stakingToken.safeTransfer(msg.sender, p.amount);
if (reward > 0) {
if (rewardAvailable() < reward) revert RewardsUnavailable();
stakingToken.safeTransfer(msg.sender, reward);
}
emit Withdrawn(msg.sender, positionId, p.amount, reward, penalty);
}
function emergencyWithdraw(uint256 positionId) external nonReentrant {
Position storage p = positions[positionId];
if (p.owner != msg.sender) revert NotPositionOwner();
if (p.withdrawn) revert PositionWithdrawn(positionId);
bool early = (p.unlockAt != 0 && block.timestamp < p.unlockAt);
if (p.hardLock && early && !emergencyUnlockAll) revert HardLockActive(positionId);
p.withdrawn = true;
totalStaked -= p.amount;
_decreasePoolPrincipal(p.poolId, p.amount);
stakingToken.safeTransfer(msg.sender, p.amount);
emit EmergencyWithdraw(msg.sender, positionId, p.amount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../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.
*
* The initial owner is set to the address provided by the deployer. 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;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling 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 {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": []
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_rewardTreasury","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AttestationFailed","type":"error"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"CompoundDisabled","type":"error"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"HardLockActive","type":"error"},{"inputs":[{"internalType":"string","name":"parameter","type":"string"}],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"MissingPresaleTokens","type":"error"},{"inputs":[],"name":"NotPositionOwner","type":"error"},{"inputs":[],"name":"NotPresale","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"PoolAccountingUnderflow","type":"error"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"PoolCapExceeded","type":"error"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"PoolDisabled","type":"error"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"PoolExpired","type":"error"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"PositionDoesNotExist","type":"error"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"PositionWithdrawn","type":"error"},{"inputs":[],"name":"ReferralOracleUnset","type":"error"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"uint256","name":"required","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"ReferralRequirementNotMet","type":"error"},{"inputs":[],"name":"RewardsUnavailable","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"UseDrainRewards","type":"error"},{"inputs":[{"internalType":"string","name":"parameter","type":"string"}],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"}],"name":"ClaimedBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardAdded","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPrincipal","type":"uint256"}],"name":"Compounded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DrainedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"penalty","type":"uint256"}],"name":"EarlyClaimPenalty","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalPenalty","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"}],"name":"EarlyClaimPenaltyBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"EmergencyUnlockAllSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"principalForfeitedReward","type":"uint256"}],"name":"EmergencyWithdraw","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":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"},{"indexed":false,"internalType":"uint32","name":"boostBpsPerTier","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"tierSize","type":"uint256"}],"name":"PoolBoostSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"maxPrincipal","type":"uint256"}],"name":"PoolCapSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"PoolCompoundSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"PoolDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"},{"indexed":false,"internalType":"uint32","name":"bpsPer1e18","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"maxBoostBps","type":"uint32"},{"indexed":false,"internalType":"bool","name":"repriceOnCompound","type":"bool"}],"name":"PoolDynamicAprSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"},{"indexed":false,"internalType":"uint256","name":"tokensPerBp1e18","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"maxBoostBps","type":"uint32"},{"indexed":false,"internalType":"bool","name":"repriceOnCompound","type":"bool"}],"name":"PoolDynamicAprStepsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"deadline","type":"uint256"},{"indexed":false,"internalType":"bool","name":"stopAccrual","type":"bool"}],"name":"PoolExpirySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"uint32","name":"maxBoostBps","type":"uint32"}],"name":"PoolMaxBoostSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"minReferrals","type":"uint256"}],"name":"PoolMinReferralsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"PoolPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"lockDuration","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"aprBps","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"earlyPenaltyBps","type":"uint32"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"},{"indexed":false,"internalType":"bool","name":"hardLock","type":"bool"}],"name":"PoolSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"PoolUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"presale","type":"address"}],"name":"PresaleContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oracle","type":"address"}],"name":"ReferralOracleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RescuedTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsFunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"principal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"penalty","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"MAX_APR_BPS","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PENALTY_BPS","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"claim","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"positionIds","type":"uint256[]"}],"name":"claimMany","outputs":[{"internalType":"uint256","name":"totalReward","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"clearReferralOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"compound","outputs":[{"internalType":"uint256","name":"rewardAdded","type":"uint256"},{"internalType":"uint256","name":"newPrincipal","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"deletePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"drainRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyUnlockAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"fundRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"getPoolBoostCaps","outputs":[{"internalType":"uint32","name":"perPoolBoostCapBps","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"getPoolDynamicConfig","outputs":[{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"uint32","name":"bpsPer1e18","type":"uint32"},{"internalType":"uint256","name":"tokensPerBp1e18","type":"uint256"},{"internalType":"uint32","name":"maxBoostBps","type":"uint32"},{"internalType":"bool","name":"repriceOnCompound","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"getPoolExpiry","outputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"stopAccrual","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"getPoolGates","outputs":[{"internalType":"uint256","name":"minReferrals","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"getPoolInfo","outputs":[{"internalType":"uint256","name":"lockDuration","type":"uint256"},{"internalType":"uint32","name":"aprBps","type":"uint32"},{"internalType":"uint32","name":"earlyPenaltyBps","type":"uint32"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"bool","name":"hardLock","type":"bool"},{"internalType":"uint256","name":"currentPrincipal","type":"uint256"},{"internalType":"uint256","name":"maxPrincipal","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserReferralCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextPositionId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"onPresaleReceive","outputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"pausePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"pending","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolBoostBpsPerTier","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolBoostTierSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolCompoundEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolDynamicAprEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolDynamicBpsPer1e18","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolDynamicMaxBoostBps","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolDynamicRepriceOnCompound","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolDynamicTokensPerBp1e18","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolExpireStopsAccrual","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolMaxBoostBps","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolMaxPrincipal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolMinReferrals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolPrincipal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolReferralBoostEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"poolStakeDeadline","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"pools","outputs":[{"internalType":"uint256","name":"lockDuration","type":"uint256"},{"internalType":"uint32","name":"aprBps","type":"uint32"},{"internalType":"uint32","name":"earlyPenaltyBps","type":"uint32"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"bool","name":"hardLock","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"positions","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"lastClaim","type":"uint256"},{"internalType":"uint256","name":"unlockAt","type":"uint256"},{"internalType":"uint32","name":"aprBps","type":"uint32"},{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"bool","name":"withdrawn","type":"bool"},{"internalType":"bool","name":"hardLock","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"positionsOf","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"presaleContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"previewAprFor","outputs":[{"internalType":"uint32","name":"baseAprBps","type":"uint32"},{"internalType":"uint32","name":"boostAprBps","type":"uint32"},{"internalType":"uint32","name":"finalAprBps","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"previewAprForAmount","outputs":[{"internalType":"uint32","name":"baseAprBps","type":"uint32"},{"internalType":"uint32","name":"referralBoostBps","type":"uint32"},{"internalType":"uint32","name":"dynamicBoostBps","type":"uint32"},{"internalType":"uint32","name":"finalAprBps","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardTreasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setEmergencyUnlockAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"uint256","name":"minRefs","type":"uint256"}],"name":"setMinReferrals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"uint256","name":"lockDuration","type":"uint256"},{"internalType":"uint32","name":"aprBps","type":"uint32"},{"internalType":"uint32","name":"earlyPenaltyBps","type":"uint32"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"bool","name":"hardLock","type":"bool"}],"name":"setPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"uint256","name":"maxPrincipal","type":"uint256"}],"name":"setPoolCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setPoolCompoundEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"uint32","name":"bpsPer1e18","type":"uint32"},{"internalType":"uint32","name":"maxBoostBps","type":"uint32"},{"internalType":"bool","name":"repriceOnCompound","type":"bool"}],"name":"setPoolDynamicAprConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"uint256","name":"tokensPerBp1e18","type":"uint256"},{"internalType":"uint32","name":"maxBoostBps","type":"uint32"},{"internalType":"bool","name":"repriceOnCompound","type":"bool"}],"name":"setPoolDynamicAprSteps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"stopAccrual","type":"bool"}],"name":"setPoolExpiry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"uint32","name":"maxBoostBps","type":"uint32"}],"name":"setPoolMaxBoostBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"presale","type":"address"}],"name":"setPresaleContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"uint32","name":"boostBpsPerTier","type":"uint32"},{"internalType":"uint256","name":"tierSize","type":"uint256"}],"name":"setReferralBoostConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oracle","type":"address"}],"name":"setReferralOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"stake","outputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"uint256","name":"attestedGlobalCount","type":"uint256"},{"internalType":"uint256","name":"attestDeadline","type":"uint256"},{"internalType":"uint256","name":"syncFee","type":"uint256"},{"internalType":"bytes","name":"attestSig","type":"bytes"}],"name":"stakeAndAttest","outputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"stakeWithPermit","outputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"uint256","name":"attestedGlobalCount","type":"uint256"},{"internalType":"uint256","name":"attestDeadline","type":"uint256"},{"internalType":"uint256","name":"syncFee","type":"uint256"},{"internalType":"bytes","name":"attestSig","type":"bytes"},{"internalType":"uint256","name":"permitDeadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"stakeWithPermitAndAttest","outputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"poolId","type":"uint8"},{"internalType":"uint256","name":"attestedGlobalCount","type":"uint256"},{"internalType":"uint256","name":"attestDeadline","type":"uint256"},{"internalType":"uint256","name":"syncFee","type":"uint256"},{"internalType":"bytes","name":"attestSig","type":"bytes"},{"internalType":"uint256","name":"permitDeadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"bool","name":"requireAttest","type":"bool"}],"name":"stakeWithPermitAndTryAttest","outputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStaked","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":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"poolId","type":"uint8"}],"name":"unpausePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userPositions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60c0346101d457601f613f2838819003918201601f19168301916001600160401b038311848410176101d85780849260409485528339810103126101d457610052602061004b836101ec565b92016101ec565b9033156101c1575f8054604051929133906001600160a01b038316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36001600160a81b0319163360ff60a01b1916175f5560018080556008556001600160a01b031690811561019657506001600160a01b0382161561015f5760805260a052604051613d279081610201823960805181818161041d015281816106a30152818161123a015281816115260152818161171e0152818161196b01528181611a6f01528181611c7d01528181611de0015281816121fa0152818161251701528181612eaf0152818161314601526132f5015260a051818181610b6401528181611cd90152612e890152f35b60405163eac0d38960e01b815260206004820152600e60248201526d726577617264547265617375727960901b6044820152606490fd5b63eac0d38960e01b81526020600482015260056024820152643a37b5b2b760d91b6044820152606490fd5b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101d45756fe60806040526004361015610011575f80fd5b5f5f3560e01c806239aad714612eea578062dea01714612e195780630225d3cc14612dfd57806308b67ee314612dcb5780630bb87ff414612d485780630c8adccc14612b5d5780630de933d614612ae157806310087fb114612abb57806314b055e414612a1b578063186fe70a146129cc5780631b187267146129505780631bcd780e146128965780631bf806cd1461285e5780631e5715121461282c57806323429c15146127f557806324fe7bf7146127915780632c297539146126935780632d261c811461265c5780632e1a7d4d146123e3578063354522cd14612308578063379607f5146120d65780633945c080146120b95780633951b8401461204f5780633f4ba83a14611ff85780634233b05f14611fc657806349580fca14611ec75780634ab346cf14611e915780635312ea8e14611d2a5780635737619814611c3957806357ef501b14611c075780635c975abb14611be25780635e1b4d9914611b8b57806363d9df8514611b6257806366d1cfb114611b305780636c8ff39214611af8578063715018a614611a9e57806372f702f314611a595780637509a0f014611a235780638035a6c41461188a578063817b1cd21461186c5780638456cb591461180b57806384ec7ce7146116ad578063899346c71461168f5780638c583eaf146116665780638da5cb5b1461163f57806390a506f11461154f578063925489a81461128d57806393707a19146111eb57806396753350146111b5578063987bc1fe1461116957806399fbab88146110d1578063a50c0dc114610941578063a7cb282b14611011578063a9bbd11414610fa9578063aa5f7e2614610ceb578063ab185a4314610cb9578063abec68f014610c81578063af6e623814610c25578063b04c495414610b93578063c7c934a114610b4e578063c8a22eb414610b2a578063d093c52314610979578063d917f2d214610941578063df7d9e94146108d3578063e20cc079146108ad578063e7c9366c14610849578063ebdaae4a1461078a578063f2fde38b14610704578063f61dbf6c14610676578063f867d46b146105c1578063fa71defa1461058f578063fb87a6351461051c578063fca3b304146105015763fe7845a714610346575f80fd5b346104b8576101403660031901126104b857600435610363612fb2565b9160a43567ffffffffffffffff81116104df5761038490369060040161302c565b61038c612fc2565b916103956134d9565b6103bf6040516103a66040826130d0565b6006815265185b5bdd5b9d60d21b60208201528661346e565b6003546001600160a01b03169081156104f257813b156104ee579184916104079383604051809681958294630100553160e61b84526084356064356044353360048801613251565b03925af180156104e3579083916104ca575b50507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690813b156104c6576104808392839260405194858094819363d505accf60e01b83526101243590610104359060c4358d303360048901613299565b03925af180156104bb576104a3575b602061049b85856130f2565b604051908152f35b6104ae8280926130d0565b6104b8578061048f565b80fd5b6040513d84823e3d90fd5b8280fd5b816104d4916130d0565b6104df57815f610419565b5080fd5b6040513d85823e3d90fd5b8480fd5b635455514f60e01b8552600485fd5b50346104b857806003193601126104b857602061049b6132da565b50346104b85760203660031901126104b85760409060ff61053b612fa2565b1681526004602090815291902080546001909101546040805192835263ffffffff808316848601529382901c9093168284015260ff9281901c83161515606083015260481c9091161515608082015260a090f35b50346104b85760203660031901126104b857604060209160ff6105b0612fa2565b168152601083522054604051908152f35b50346104b85760203660031901126104b8576001600160a01b036105e3613016565b168152600660205260408120604051908160208254918281520190819285526020852090855b818110610660575050508261061f9103836130d0565b604051928392602084019060208552518091526040840192915b818110610647575050500390f35b8251845285945060209384019390920191600101610639565b8254845260209093019260019283019201610609565b50346104b85760c03660031901126104b857600435610693612fb2565b9160643560ff811681036104df577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690813b156104c6576104808392839260405194858094819363d505accf60e01b835260a43590608435906044358d303360048901613299565b50346104b85760203660031901126104b85761071e613016565b61072661337d565b6001600160a01b031680156107765781546001600160a01b03198116821783556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b631e4fbdf760e01b82526004829052602482fd5b50346104b85760203660031901126104b85760e09060ff6107a9612fa2565b16908181526004602052604081209160806040516107c681613083565b6001855495868352015490604063ffffffff83169586602084015263ffffffff8460201c1692838382015260ff8086851c1615159586606084015260481c1615159586910152858152600960205281812054958152600a602052205494604051968752602087015260408601526060850152608084015260a083015260c0820152f35b50346104b85760403660031901126104b857610863612fa2565b7fdf16ab9df51689f43633c20f576632423a8c4a79c94c4e61a44582342620b25d602060ff6024359361089461337d565b1692838552600b8252806040862055604051908152a280f35b50346104b857806003193601126104b857602060ff60035460a01c166040519015158152f35b50346104b85760203660031901126104b8576004358015158091036104df5760207f9ac7dac323f34bae913806230ea6328d8f7a2abaff593e97750bd9a9be8ec8029161091e61337d565b6003805460ff60a01b191660a083901b60ff60a01b16179055604051908152a180f35b50346104b85760203660031901126104b85763ffffffff604060209260ff610967612fa2565b168152600f8452205416604051908152f35b50346104b85760203660031901126104b85760ff610995612fa2565b61099d61337d565b1680825260096020526040822054610af0578082526004602052816001604082208281550155808252600a602052816040812055808252600b602052816040812055808252600c6020526040822060ff198154169055808252600d6020526040822063ffffffff198154169055808252600e602052816040812055808252600f6020526040822063ffffffff19815416905580825260126020526040822060ff198154169055808252601060205281604081205580825260116020526040822060ff19815416905580825260136020526040822060ff19815416905580825260146020526040822063ffffffff19815416905580825260156020526040822063ffffffff19815416905580825260166020526040822060ff19815416905580825260176020528160408120557f07800a3a235962830c0bd6e88fce6b39d9a6a7726b182f94b15de695fd7201e68280a280f35b60405162461bcd60e51b81526020600482015260126024820152711c1bdbdb081a185cc81c1c9a5b98da5c185b60721b6044820152606490fd5b50346104b85760203660031901126104b857602061049b610b49613016565b613c1c565b50346104b857806003193601126104b8576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346104b85760203660031901126104b857610bad613016565b610bb561337d565b610bdf604051610bc66040826130d0565b60068152656f7261636c6560d01b602082015282613b54565b600380546001600160a01b0319166001600160a01b039290921691821790557f188cb754c518e3db2a5a6f2c7e05e8924d9c600fdb7d70eb8a8e9a78cefe749a8280a280f35b50346104b85760203660031901126104b857600435908181526005602052610c4f60408220613198565b80519092906001600160a01b031615610c6e57602061049b4285613980565b63099532a760e31b825260045260249150fd5b50346104b85760203660031901126104b85763ffffffff604060209260ff610ca7612fa2565b16815260158452205416604051908152f35b50346104b85760203660031901126104b857604060209160ff610cda612fa2565b168152600b83522054604051908152f35b50346104b85760203660031901126104b857600435610d086133a3565b610d106134d9565b8082526005602052604082208054909183916001600160a01b03163303610f9a57600583019384549460ff8660281c16610f865760ff8660201c1695868552601260205260ff60408620541615610f7257610d6a876135be565b610d7c42610d7788613198565b613980565b426003880155928315610f5d5750839087865260046020526040862090600160405192610da884613083565b8054845201549163ffffffff83166020820152608060ff63ffffffff8560201c1694856040850152818160401c161515606085015260481c1615159101526004880154908115159182610f52575b5060301c60ff16159081610f4a575b5080610f41575b610ee4575b505081610e1c6132da565b10610ed557610e2d8260409761364a565b6001829501610e3d838254613177565b8155610e4b83600754613177565b60075554809460ff8881855460201c16928381526016602052205416610eb0575b50505084519081528260208201527fb64fdfe595e3a4a34d54b4ed776c5277108675a5a16909998d6ba9a6484dc78d853392a35b6001805582519182526020820152f35b63ffffffff91610ec09133613b82565b1663ffffffff198254161790555f8381610e6c565b636e2d286560e11b8452600484fd5b610ef16127109185613213565b0492808411610f39575b83610f0591613244565b926040519081527f51dd30497f5f377d33b9478808ca4dab456aa7fbffb66ec8adef09a139592ad760203392a3825f610e11565b925082610efb565b50801515610e0c565b90505f610e05565b4210915060ff610df6565b95935050505060409350600191500154610ea0565b6314fce3f760e11b85526004879052602485fd5b6321b5e5af60e01b84526004839052602484fd5b6370d645e360e01b8252600482fd5b50346104b85760203660031901126104b857610fc3613016565b610fcb61337d565b600280546001600160a01b0319166001600160a01b039290921691821790557f7188527286b7c8f39703bf108a472dc431dec1ab5e61b363c3ebb1f35ef67af18280a280f35b50346104b85760803660031901126104b85761102b612fa2565b7fb4467e799ded272c661fae9d93dddcd4288f2e4c2ea87d0d76147f78424d4a306060611056613007565b61105e612fd2565b9363ffffffff60ff6064359261107261337d565b1695868852600c6020526110958460408a209060ff801983541691151516179055565b868852600d602052604088208282168319825416179055868852600e60205282604089205560405193151584521660208301526040820152a280f35b50346104b85760203660031901126104b857604061012091600435815260056020522060ff60018060a01b038254169160018101549060028101546003820154906005600484015493015493604051968752602087015260408601526060850152608084015263ffffffff811660a0840152818160201c1660c0840152818160281c16151560e084015260301c161515610100820152f35b50346104b85760203660031901126104b85760ff604081611188612fa2565b16808452601060209081528285205491855260118152919093205460408051948552921615159083015290f35b50346104b85760203660031901126104b85760ff6040602092826111d7612fa2565b168152601184522054166040519015158152f35b50346104b85760203660031901126104b85760043561120861337d565b6112326040516112196040826130d0565b6006815265185b5bdd5b9d60d21b60208201528261346e565b61125e8130337f00000000000000000000000000000000000000000000000000000000000000006136ae565b6040519081527fd53214ca07be5520e229c395f05a3e5c0697ec6279184ffbe2758d304fd322cc60203392a280f35b50346104b85760203660031901126104b8576004359067ffffffffffffffff82116104b857366023830112156104b85781600401359067ffffffffffffffff82116104b8573660248360051b850101116104b8576112e96133a3565b6112f16134d9565b808093815b848110156114845760248160051b83010135808452600560205260408420903360018060a01b03835416036114755760058201549060ff8260281c16611463575061134442610d7784613198565b908161135c575b5050426003909101556001016112f6565b60ff816020989394981c1686526004602052604086209060016040519261138284613083565b8054845201549163ffffffff83166020820152608060ff63ffffffff8560201c1694856040850152818160401c161515606085015260481c1615159101526004880154908115159182611458575b5060301c60ff16159081611450575b5080611447575b611402575b50600192916113f991613177565b9490915f61134b565b976114358361271061141b6113f9959c60019897613213565b049080821161143f575b8161142f91613244565b92613177565b98915091926113eb565b905080611425565b508015156113e6565b90505f6113df565b4210915060ff6113d0565b6321b5e5af60e01b8652600452602485fd5b6370d645e360e01b8552600485fd5b505091838261150d575b60209350806114d6575b5060405190828252838201527fd117f41d50ccfc0f62d15c908ef0c1f8aa8138e21bb22bcf6f9f60a147af440860403392a260018055604051908152f35b60405190815281848201527f4614a922d4b631d68d17e86a5b3e77c61f0e7ead56c4776dc95e0ef093bf95ad60403392a283611498565b826115166132da565b10610ed5576020935061154a83337f0000000000000000000000000000000000000000000000000000000000000000613497565b61148e565b50346104b85760a03660031901126104b857611569612fa2565b7fc84a9f1e745bce22ad9de1585ff0557730706c0f8be5271478de0c3a3b0672246080611594613007565b6044359363ffffffff6115a5612fe5565b60ff6115af612ff8565b936115b861337d565b169687895260136020526115db8560408b209060ff801983541691151516179055565b87895260176020528060408a2055878952601560205260408920838316841982541617905587895260166020526116218460408b209060ff801983541691151516179055565b6040519415158552602085015216604083015215156060820152a280f35b50346104b857806003193601126104b857546040516001600160a01b039091168152602090f35b50346104b857806003193601126104b8576003546040516001600160a01b039091168152602090f35b50346104b857806003193601126104b8576020600854604051908152f35b506101603660031901126104b8576004356116c6612fb2565b9160a43567ffffffffffffffff81116104df576116e790369060040161302c565b906116f0612fc2565b91610144359182151583036104ee576117076134d9565b6003546001600160a01b03169081611784575b50507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692915050813b156104c6576104808392839260405194858094819363d505accf60e01b83526101243590610104359060c4358d303360048901613299565b813b15611807576117ba928692839283604051809781958294630100553160e61b84526084356064356044353360048801613251565b03925af191826117ee575b50506117e8576117d9575b5f80808061171a565b630c7ae0a360e31b8252600482fd5b506117d0565b816117f8916130d0565b61180357835f6117c5565b8380fd5b8580fd5b50346104b857806003193601126104b85761182461337d565b61182c6134d9565b805460ff60a01b1916600160a01b1781556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602090a180f35b50346104b857806003193601126104b8576020600754604051908152f35b50346104b85760603660031901126104b8576118a4613016565b6024356044359160ff83168303611803576118bd6133a3565b6118c56134d9565b6002546001600160a01b03163303611a14576118ff6040516118e86040826130d0565b60048152633ab9b2b960e11b602082015282613b54565b6119296040516119106040826130d0565b6006815265185b5bdd5b9d60d21b60208201528361346e565b6119328361351f565b9361193c846135be565b61194684836135fe565b611950838561364a565b6040516370a0823160e01b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156104bb5782916119de575b506119b084600754613177565b116119cf5760206119c3868686866136f2565b60018055604051908152f35b6335f6978b60e21b8152600490fd5b90506020813d602011611a0c575b816119f9602093836130d0565b81010312611a0857515f6119a3565b5f80fd5b3d91506119ec565b6318852ca560e11b8452600484fd5b50346104b85760203660031901126104b85760ff604060209282611a45612fa2565b168152601284522054166040519015158152f35b50346104b857806003193601126104b8576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346104b857806003193601126104b857611ab761337d565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346104b85760203660031901126104b85763ffffffff604060209260ff611b1e612fa2565b16815260148452205416604051908152f35b50346104b85760203660031901126104b857604060209160ff611b51612fa2565b168152600983522054604051908152f35b50346104b857806003193601126104b8576002546040516001600160a01b039091168152602090f35b50346104b85760403660031901126104b857611ba5613016565b6001600160a01b03168152600660205260408120805460243592908310156104b8576020611bd3848461305a565b90549060031b1c604051908152f35b50346104b857806003193601126104b85760ff6020915460a01c166040519015158152f35b50346104b85760203660031901126104b857604060209160ff611c28612fa2565b168152600e83522054604051908152f35b50346104b85760403660031901126104b857611c53613016565b60243590611c5f61337d565b611c676133a3565b611c6f6133f9565b6001600160a01b03908116907f0000000000000000000000000000000000000000000000000000000000000000168114611d1b57611cb46040516119106040826130d0565b7f0f51b71e5e9ee881072b57bf4022b60435e0000ad377b5c1434da39471002b5560207f0000000000000000000000000000000000000000000000000000000000000000611d03858286613497565b6040519485526001600160a01b031693a36001805580f35b63d667159760e01b8352600483fd5b50346104b85760203660031901126104b857600435611d476133a3565b80825260056020526040822080546001600160a01b03163303611e82576005810190815460ff8160281c16611e6e5760048201548015159081611e64575b5060ff8260301c169081611e5c575b5080611e4c575b611e38576001611dd8926501000000000060ff9360ff60281b19161785550192611dc88454600754613244565b6007555460201c16825490613a62565b611e048154337f0000000000000000000000000000000000000000000000000000000000000000613497565b546040519081527fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae059560203392a36001805580f35b633e2fa97b60e01b85526004849052602485fd5b5060ff60035460a01c1615611d9b565b90505f611d94565b905042105f611d85565b6321b5e5af60e01b85526004849052602485fd5b6370d645e360e01b8352600483fd5b50346104b85760203660031901126104b85760ff604060209282611eb3612fa2565b168152600c84522054166040519015158152f35b34611a085760c0366003190112611a0857600435611ee3612fb2565b9060a43567ffffffffffffffff8111611a0857611f0490369060040161302c565b9290611f0e6134d9565b611f38604051611f1f6040826130d0565b6006815265185b5bdd5b9d60d21b60208201528461346e565b6003546001600160a01b0316938415611fb757843b15611a0857611f7f945f9283604051809881958294630100553160e61b84526084356064356044353360048801613251565b03925af1918215611fac5760209361049b93611f9c575b506130f2565b5f611fa6916130d0565b5f611f96565b6040513d5f823e3d90fd5b635455514f60e01b5f5260045ffd5b34611a08576020366003190112611a085760ff611fe1612fa2565b165f52600b602052602060405f2054604051908152f35b34611a08575f366003190112611a085761201061337d565b6120186133f9565b60ff60a01b195f54165f557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b34611a08576020366003190112611a085760ff61206a612fa2565b61207261337d565b16805f526004602052600160405f2001600160401b60ff60401b198254161790557ff78f5478f78ece65f53391387442d39e2760ea7455616d157657f461a0e517e95f80a2005b34611a08575f366003190112611a08576020604051620f42408152f35b34611a08576020366003190112611a08576004356120f26133a3565b6120fa6134d9565b5f81815260056020526040902080549091906001600160a01b031633036122f95760058201549060ff8260281c166122e75760ff8260201c165f52600460205260405f2060016040519161214d83613083565b8054835201549063ffffffff82166020820152608060ff604083019363ffffffff8160201c168552818160401c161515606085015260481c16151591015261219842610d7786613198565b92426003860155836121b4575b60208460018055604051908152f35b6004839501549081151591826122dc575b5060301c60ff161590816122d4575b50806122c4575b612260575b5050806121eb6132da565b106122515760209161221e82337f0000000000000000000000000000000000000000000000000000000000000000613497565b6040518281527f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a843392a38280806121a5565b636e2d286560e11b5f5260045ffd5b61227463ffffffff61271092511684613213565b04918083116122bc575b8261228891613244565b916040519081527f51dd30497f5f377d33b9478808ca4dab456aa7fbffb66ec8adef09a139592ad760203392a381836121e0565b91508161227e565b5063ffffffff81511615156121db565b9050856121d4565b4210915060ff6121c5565b6321b5e5af60e01b5f5260045260245ffd5b6370d645e360e01b5f5260045ffd5b34611a08576060366003190112611a08576080612323613016565b63ffffffff612330612fb2565b60ff81165f5260046020528161239a6123918360405f20966001604051986123578a613083565b80548a520154978960ff878b169a8b6020850152888160201c166040850152818160401c161515606085015260481c1615159101526138ca565b92604435613aa6565b9116906123b4836123ab8487613177565b92168092613177565b91620f424083116123d8575b60405194855260208501526040840152166060820152f35b620f424092506123c0565b34611a08576020366003190112611a08576004356123ff6133a3565b6124076134d9565b5f81815260056020526040902080546001600160a01b031633036122f957600581019081549160ff8360281c166126495760ff8360201c165f52600460205260405f209160016040519361245a85613083565b8054855201549263ffffffff84166020820152608060ff604083019563ffffffff8160201c168752818160401c161515606085015260481c1615159101526124a542610d7783613198565b935f936004830154801515908161263f575b5060ff8360301c16808091612638575b80612628575b6126155715908161260d575b50806125fd575b806125f4575b6125a7575b506001612515926501000000000060ff9360ff60281b19161785550192611dc88454600754613244565b7f000000000000000000000000000000000000000000000000000000000000000061254282543383613497565b83612587575b505491604051928352602083015260408201527f94ffd6b85c71b847775c89ef6496b93cee961bdc6ff827fd117f174f06f745ae60603392a360018055005b836125906132da565b1061225157836125a1913390613497565b84612548565b60ff91959450612515926127106125c763ffffffff600194511688613213565b048681116125ed575b6125e281650100000000009298613244565b9793505092506124eb565b50856125d0565b508515156124e6565b5063ffffffff81511615156124e0565b9050886124d9565b88633e2fa97b60e01b5f5260045260245ffd5b5060ff60035460a01c16156124cd565b50816124c7565b90504210886124b7565b836321b5e5af60e01b5f5260045260245ffd5b34611a08576020366003190112611a085760ff612677612fa2565b165f526013602052602060ff60405f2054166040519015158152f35b34611a085760a0366003190112611a08576126ac612fa2565b7f699fa7f866be5cc1e82d7b656cc2621a932f59229af77660482cb772c24a66cc60806126d7613007565b6126df612fd2565b9363ffffffff6126ed612fe5565b8160ff6126f8612ff8565b9461270161337d565b1697885f5260136020526127248660405f209060ff801983541691151516179055565b885f52601460205260405f208282168319825416179055885f52601560205260405f208284168319825416179055885f5260166020526127738560405f209060ff801983541691151516179055565b604051951515865216602085015216604083015215156060820152a2005b34611a08576020366003190112611a085760ff6127ac612fa2565b6127b461337d565b16805f526004602052600160405f200160ff60401b1981541690557feaefa8d4750e7ddb7f90ca7d00bc6712996a0e1d7880878a7f4443f60b12941e5f80a2005b34611a08576020366003190112611a085760ff612810612fa2565b165f526016602052602060ff60405f2054166040519015158152f35b34611a08576020366003190112611a085760ff612847612fa2565b165f52600a602052602060405f2054604051908152f35b34611a08576020366003190112611a085760ff612879612fa2565b165f52600d602052602063ffffffff60405f205416604051908152f35b34611a08576040366003190112611a085760606128b1613016565b63ffffffff8061291b6128c2612fb2565b60ff81165f52600460205260405f20946001604051966128e188613083565b80548852015495608060ff86891698896020850152878160201c166040850152818160401c1615158b85015260481c1615159101526138ca565b166129268184613177565b90620f42408211612945575b6040519384526020840152166040820152f35b620f42409150612932565b34611a08576040366003190112611a0857612969612fa2565b7fe2bcc00690eab73769ac4b6a16a5aae08c82855fd488fcd96232b9f21f0d8a47602060ff612996613007565b9361299f61337d565b1692835f52601282526129c18160405f209060ff801983541691151516179055565b6040519015158152a2005b34611a08575f366003190112611a08576129e461337d565b600380546001600160a01b03191690555f7f188cb754c518e3db2a5a6f2c7e05e8924d9c600fdb7d70eb8a8e9a78cefe749a8180a2005b34611a08576060366003190112611a0857612a34612fa2565b602435906044358015158103611a085760ff7fb1ef9117b124c174ccab2ce3989bee1611d4e237c320a902ebf1db72abc9e2d092612a7061337d565b1692835f5260106020528060405f2055835f526011602052612aa18260405f209060ff801983541691151516179055565b60408051918252911515602082015290819081015b0390a2005b34611a08576040366003190112611a0857602061049b612ad9612fb2565b6004356130f2565b34611a08576040366003190112611a0857612afa612fa2565b6024359063ffffffff8216809203611a0857602060ff7fb02ac62f2bf80f694ec18bcd8af98c1703c1c37db5efaaaf422c2895da500a0c92612b3a61337d565b1692835f52600f825260405f208163ffffffff19825416179055604051908152a2005b34611a085760c0366003190112611a0857612b76612fa2565b60243590612b82612fd2565b612b8a612fe5565b92612b93612ff8565b9360a43580151595868203611a0857612baa61337d565b63ffffffff851692620f42408411612d145763ffffffff8116936127108511612cdc5760ff987f3b3175e1b9486521504d84a3af309d0efa648c74f06664f2759977852d637f4a98612ab69663ffffffff8060016040519e8f95612c0d87613083565b8d87526020870198895260408701958652608060608801978c1515895201978852169e8f5f52600460205260405f2090518155019551161663ffffffff198554161784555167ffffffff0000000084549160201b169067ffffffff00000000191617835551151560ff60401b83549160401b169060ff60401b191617825551151560ff60481b82549160481b169060ff60481b191617905560405195869586939095949160809363ffffffff809260a08801998852166020870152166040850152151560608401521515910152565b60405162461bcd60e51b815260206004820152601060248201526f0e0cadcc2d8e8f240e8dede40d0d2ced60831b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b0c2e0e440e8dede40d0d2ced60a31b6044820152606490fd5b34611a08576020366003190112611a085760a060ff612d65612fa2565b165f90815260136020908152604080832054601483528184205460178452828520546015855283862054601686529584902054845160ff9485161515815263ffffffff938416968101969096529385015293909316606083015290911615156080820152f35b34611a08576020366003190112611a085760ff612de6612fa2565b165f526017602052602060405f2054604051908152f35b34611a08575f366003190112611a085760206040516127108152f35b34611a08576020366003190112611a0857600435612e3561337d565b612e3d6133a3565b612e456133f9565b612e566040516112196040826130d0565b80612e5f6132da565b10612251577f2681c455422749afc6dceefd75dd0274b9b3cbf96e31023dc344731b78e7261f60207f0000000000000000000000000000000000000000000000000000000000000000612ed384827f0000000000000000000000000000000000000000000000000000000000000000613497565b6040519384526001600160a01b031692a260018055005b34611a08576040366003190112611a0857612f03612fa2565b60243590612f0f61337d565b81151580612f8a575b612f5a57602060ff7f7baa46cf0c4587615b98f7870e63472ae3d772624f6dc0dbe54f4672cab9f1d2921692835f52600a82528060405f2055604051908152a2005b60405163589956a560e11b81526020600482015260076024820152660706f6f6c4361760cc1b6044820152606490fd5b5060ff81165f52600960205260405f20548210612f18565b6004359060ff82168203611a0857565b6024359060ff82168203611a0857565b60e4359060ff82168203611a0857565b6044359063ffffffff82168203611a0857565b6064359063ffffffff82168203611a0857565b608435908115158203611a0857565b602435908115158203611a0857565b600435906001600160a01b0382168203611a0857565b9181601f84011215611a085782359167ffffffffffffffff8311611a085760208381860195010111611a0857565b805482101561306f575f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b60a0810190811067ffffffffffffffff82111761309f57604052565b634e487b7160e01b5f52604160045260245ffd5b610120810190811067ffffffffffffffff82111761309f57604052565b90601f8019910116810190811067ffffffffffffffff82111761309f57604052565b613170916130fe6133a3565b6131066134d9565b6131176040516119106040826130d0565b6131208161351f565b9161312a826135be565b61313482336135fe565b61313e818361364a565b61316a8130337f00000000000000000000000000000000000000000000000000000000000000006136ae565b336136f2565b9060018055565b9190820180921161318457565b634e487b7160e01b5f52601160045260245ffd5b906040516131a5816130b3565b61010060ff6005839560018060a01b03815416855260018101546020860152600281015460408601526003810154606086015260048101546080860152015463ffffffff811660a0850152818160201c1660c0850152818160281c16151560e085015260301c161515910152565b8181029291811591840414171561318457565b8115613230570490565b634e487b7160e01b5f52601260045260245ffd5b9190820391821161318457565b9491928694919360c0979460018060a01b0316875260208701526040860152606085015260a060808501528160a0850152848401375f828201840152601f01601f1916010190565b9360c095919897969360ff9360e087019a60018060a01b0316875260018060a01b031660208701526040860152606085015216608083015260a08201520152565b6040516370a0823160e01b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115611fac575f9161334b575b50600754808211156133455761334291613244565b90565b50505f90565b90506020813d602011613375575b81613366602093836130d0565b81010312611a0857515f61332d565b3d9150613359565b5f546001600160a01b0316330361339057565b63118cdaa760e01b5f523360045260245ffd5b6002600154146133b4576002600155565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60ff5f5460a01c161561340857565b60405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606490fd5b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b156134765750565b60405163589956a560e11b81529081906134939060048301613444565b0390fd5b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044808301939093529181526134d7916134d26064836130d0565b613c99565b565b60ff5f5460a01c166134e757565b60405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606490fd5b60ff905f608060405161353181613083565b82815282602082015282604082015282606082015201521690815f52600460205260405f209160016040519361356685613083565b8054855201549263ffffffff8416602082015263ffffffff8460201c16604082015260ff808560401c1615948515606084015260481c1615156080820152926135ac5750565b63788ff61160e11b5f5260045260245ffd5b60ff16805f52601060205260405f205480159081156135f3575b50156135e15750565b63ed2bea4b60e01b5f5260045260245ffd5b90504211155f6135d8565b9060ff1690815f52600b60205260405f20549081156136455761362090613c1c565b9181831061362d57505050565b63a3d470c360e01b5f5260045260245260445260645ffd5b505050565b60ff16805f52600a60205260405f20548061367b575b505f52600960205261367760405f20918254613177565b9055565b815f526009602052806136928460405f2054613177565b1115613660579063db914f1b60e01b5f5260045260245260445ffd5b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526134d7916134d26084836130d0565b60085492949390915f19841461318457600184016008558395613716828286613b82565b9085845180155f146138b8575060805f955b015115159163ffffffff806005604051996137428b6130b3565b60018060a01b0316998a81526020810199898b52604082014281526060830190428252608084019283528560a085019b168b5260ff60c0850198169c8d895260e08501995f8b5261010086019b8c525f528560205260405f209460018060a01b039051166bffffffffffffffffffffffff60a01b865416178555516001850155516002840155516003830155516004820155019551161663ffffffff198554161784555164ff0000000084549160201b169064ff00000000191617835551151560ff60281b83549160281b169060ff60281b191617825551151566ff00000000000082549160301b169066ff0000000000001916179055825f52600660205260405f2091825491600160401b83101561309f57613888837fbde7f0ba1630d25515c7ab99ba47d5640b7ffb4c673b2a5464ae67919558929895600160409601815561305a565b81549060031b9088821b915f19901b19161790556138a881600754613177565b60075582519182526020820152a3565b6138c460809142613177565b95613728565b9060ff1690815f52600c60205260ff60405f2054161561334557815f52600e60205260405f2054908115613979576139269161390861390d92613c1c565b613226565b825f52600d60205263ffffffff60405f20541690613213565b905f52600f60205263ffffffff60405f20541680151580613970575b613968575b5063ffffffff811161395d575b63ffffffff1690565b5063ffffffff613954565b90505f613947565b50808211613942565b5050505f90565b9060e082015115801590613a54575b61334557608082015180613a3f57505b8060c0830160ff8151165f52601160205260ff60405f205416613a03575b505060608201519182821115613979576139fa6139e364496cebb800946139ff94613244565b9163ffffffff60a060208301519201511690613213565b613213565b0490565b60ff9051165f52601060205260405f205490818015159182613a35575b5050613a2d575b806139bd565b90505f613a27565b119050815f613a20565b80821015613a4d575061399f565b905061399f565b50606082015181111561398f565b60ff1690815f52600960205260405f2054818110613a935790613a8491613244565b905f52600960205260405f2055565b8263218a315960e01b5f5260045260245ffd5b9060ff16805f52601360205260ff60405f205416158015613b4c575b61334557805f52601560205263ffffffff60405f20541691815f52601760205260405f2054918215155f14613b1f575090613afc91613226565b905b8015158061397057613968575063ffffffff811161395d5763ffffffff1690565b613b4692505f526014602052670de0b6b3a764000063ffffffff60405f2054169104613213565b90613afe565b508115613ac2565b6001600160a01b031615613b655750565b60405163eac0d38960e01b81529081906134939060048301613444565b613bf2613bff9392613bf963ffffffff9360ff83165f52600460205284613bf28460405f2093600160405195613bb787613083565b80548752015494608060ff86881697886020850152878160201c166040850152818160401c161515606085015260481c1615159101526138ca565b1690613177565b93613aa6565b620f42408111613c125763ffffffff1690565b50620f4240613954565b6003546001600160a01b03169081156133455760405163db74559b60e01b81526001600160a01b03909116600482015290602090829060249082905afa908115611fac575f91613c6a575090565b90506020813d602011613c91575b81613c85602093836130d0565b81010312611a08575190565b3d9150613c78565b905f602091828151910182855af115611fac575f513d613ce857506001600160a01b0381163b155b613cc85750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415613cc156fea26469706673582212201250440bd948a4b35dfab8babb6cbec4f04363b14c63ee369a1b4f419f5f58c964736f6c634300081e0033000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b00000000000000000000000098d7674011daea6c0cac896af80443b6b0200e3c
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f5f3560e01c806239aad714612eea578062dea01714612e195780630225d3cc14612dfd57806308b67ee314612dcb5780630bb87ff414612d485780630c8adccc14612b5d5780630de933d614612ae157806310087fb114612abb57806314b055e414612a1b578063186fe70a146129cc5780631b187267146129505780631bcd780e146128965780631bf806cd1461285e5780631e5715121461282c57806323429c15146127f557806324fe7bf7146127915780632c297539146126935780632d261c811461265c5780632e1a7d4d146123e3578063354522cd14612308578063379607f5146120d65780633945c080146120b95780633951b8401461204f5780633f4ba83a14611ff85780634233b05f14611fc657806349580fca14611ec75780634ab346cf14611e915780635312ea8e14611d2a5780635737619814611c3957806357ef501b14611c075780635c975abb14611be25780635e1b4d9914611b8b57806363d9df8514611b6257806366d1cfb114611b305780636c8ff39214611af8578063715018a614611a9e57806372f702f314611a595780637509a0f014611a235780638035a6c41461188a578063817b1cd21461186c5780638456cb591461180b57806384ec7ce7146116ad578063899346c71461168f5780638c583eaf146116665780638da5cb5b1461163f57806390a506f11461154f578063925489a81461128d57806393707a19146111eb57806396753350146111b5578063987bc1fe1461116957806399fbab88146110d1578063a50c0dc114610941578063a7cb282b14611011578063a9bbd11414610fa9578063aa5f7e2614610ceb578063ab185a4314610cb9578063abec68f014610c81578063af6e623814610c25578063b04c495414610b93578063c7c934a114610b4e578063c8a22eb414610b2a578063d093c52314610979578063d917f2d214610941578063df7d9e94146108d3578063e20cc079146108ad578063e7c9366c14610849578063ebdaae4a1461078a578063f2fde38b14610704578063f61dbf6c14610676578063f867d46b146105c1578063fa71defa1461058f578063fb87a6351461051c578063fca3b304146105015763fe7845a714610346575f80fd5b346104b8576101403660031901126104b857600435610363612fb2565b9160a43567ffffffffffffffff81116104df5761038490369060040161302c565b61038c612fc2565b916103956134d9565b6103bf6040516103a66040826130d0565b6006815265185b5bdd5b9d60d21b60208201528661346e565b6003546001600160a01b03169081156104f257813b156104ee579184916104079383604051809681958294630100553160e61b84526084356064356044353360048801613251565b03925af180156104e3579083916104ca575b50507f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b6001600160a01b031690813b156104c6576104808392839260405194858094819363d505accf60e01b83526101243590610104359060c4358d303360048901613299565b03925af180156104bb576104a3575b602061049b85856130f2565b604051908152f35b6104ae8280926130d0565b6104b8578061048f565b80fd5b6040513d84823e3d90fd5b8280fd5b816104d4916130d0565b6104df57815f610419565b5080fd5b6040513d85823e3d90fd5b8480fd5b635455514f60e01b8552600485fd5b50346104b857806003193601126104b857602061049b6132da565b50346104b85760203660031901126104b85760409060ff61053b612fa2565b1681526004602090815291902080546001909101546040805192835263ffffffff808316848601529382901c9093168284015260ff9281901c83161515606083015260481c9091161515608082015260a090f35b50346104b85760203660031901126104b857604060209160ff6105b0612fa2565b168152601083522054604051908152f35b50346104b85760203660031901126104b8576001600160a01b036105e3613016565b168152600660205260408120604051908160208254918281520190819285526020852090855b818110610660575050508261061f9103836130d0565b604051928392602084019060208552518091526040840192915b818110610647575050500390f35b8251845285945060209384019390920191600101610639565b8254845260209093019260019283019201610609565b50346104b85760c03660031901126104b857600435610693612fb2565b9160643560ff811681036104df577f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b6001600160a01b031690813b156104c6576104808392839260405194858094819363d505accf60e01b835260a43590608435906044358d303360048901613299565b50346104b85760203660031901126104b85761071e613016565b61072661337d565b6001600160a01b031680156107765781546001600160a01b03198116821783556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b631e4fbdf760e01b82526004829052602482fd5b50346104b85760203660031901126104b85760e09060ff6107a9612fa2565b16908181526004602052604081209160806040516107c681613083565b6001855495868352015490604063ffffffff83169586602084015263ffffffff8460201c1692838382015260ff8086851c1615159586606084015260481c1615159586910152858152600960205281812054958152600a602052205494604051968752602087015260408601526060850152608084015260a083015260c0820152f35b50346104b85760403660031901126104b857610863612fa2565b7fdf16ab9df51689f43633c20f576632423a8c4a79c94c4e61a44582342620b25d602060ff6024359361089461337d565b1692838552600b8252806040862055604051908152a280f35b50346104b857806003193601126104b857602060ff60035460a01c166040519015158152f35b50346104b85760203660031901126104b8576004358015158091036104df5760207f9ac7dac323f34bae913806230ea6328d8f7a2abaff593e97750bd9a9be8ec8029161091e61337d565b6003805460ff60a01b191660a083901b60ff60a01b16179055604051908152a180f35b50346104b85760203660031901126104b85763ffffffff604060209260ff610967612fa2565b168152600f8452205416604051908152f35b50346104b85760203660031901126104b85760ff610995612fa2565b61099d61337d565b1680825260096020526040822054610af0578082526004602052816001604082208281550155808252600a602052816040812055808252600b602052816040812055808252600c6020526040822060ff198154169055808252600d6020526040822063ffffffff198154169055808252600e602052816040812055808252600f6020526040822063ffffffff19815416905580825260126020526040822060ff198154169055808252601060205281604081205580825260116020526040822060ff19815416905580825260136020526040822060ff19815416905580825260146020526040822063ffffffff19815416905580825260156020526040822063ffffffff19815416905580825260166020526040822060ff19815416905580825260176020528160408120557f07800a3a235962830c0bd6e88fce6b39d9a6a7726b182f94b15de695fd7201e68280a280f35b60405162461bcd60e51b81526020600482015260126024820152711c1bdbdb081a185cc81c1c9a5b98da5c185b60721b6044820152606490fd5b50346104b85760203660031901126104b857602061049b610b49613016565b613c1c565b50346104b857806003193601126104b8576040517f00000000000000000000000098d7674011daea6c0cac896af80443b6b0200e3c6001600160a01b03168152602090f35b50346104b85760203660031901126104b857610bad613016565b610bb561337d565b610bdf604051610bc66040826130d0565b60068152656f7261636c6560d01b602082015282613b54565b600380546001600160a01b0319166001600160a01b039290921691821790557f188cb754c518e3db2a5a6f2c7e05e8924d9c600fdb7d70eb8a8e9a78cefe749a8280a280f35b50346104b85760203660031901126104b857600435908181526005602052610c4f60408220613198565b80519092906001600160a01b031615610c6e57602061049b4285613980565b63099532a760e31b825260045260249150fd5b50346104b85760203660031901126104b85763ffffffff604060209260ff610ca7612fa2565b16815260158452205416604051908152f35b50346104b85760203660031901126104b857604060209160ff610cda612fa2565b168152600b83522054604051908152f35b50346104b85760203660031901126104b857600435610d086133a3565b610d106134d9565b8082526005602052604082208054909183916001600160a01b03163303610f9a57600583019384549460ff8660281c16610f865760ff8660201c1695868552601260205260ff60408620541615610f7257610d6a876135be565b610d7c42610d7788613198565b613980565b426003880155928315610f5d5750839087865260046020526040862090600160405192610da884613083565b8054845201549163ffffffff83166020820152608060ff63ffffffff8560201c1694856040850152818160401c161515606085015260481c1615159101526004880154908115159182610f52575b5060301c60ff16159081610f4a575b5080610f41575b610ee4575b505081610e1c6132da565b10610ed557610e2d8260409761364a565b6001829501610e3d838254613177565b8155610e4b83600754613177565b60075554809460ff8881855460201c16928381526016602052205416610eb0575b50505084519081528260208201527fb64fdfe595e3a4a34d54b4ed776c5277108675a5a16909998d6ba9a6484dc78d853392a35b6001805582519182526020820152f35b63ffffffff91610ec09133613b82565b1663ffffffff198254161790555f8381610e6c565b636e2d286560e11b8452600484fd5b610ef16127109185613213565b0492808411610f39575b83610f0591613244565b926040519081527f51dd30497f5f377d33b9478808ca4dab456aa7fbffb66ec8adef09a139592ad760203392a3825f610e11565b925082610efb565b50801515610e0c565b90505f610e05565b4210915060ff610df6565b95935050505060409350600191500154610ea0565b6314fce3f760e11b85526004879052602485fd5b6321b5e5af60e01b84526004839052602484fd5b6370d645e360e01b8252600482fd5b50346104b85760203660031901126104b857610fc3613016565b610fcb61337d565b600280546001600160a01b0319166001600160a01b039290921691821790557f7188527286b7c8f39703bf108a472dc431dec1ab5e61b363c3ebb1f35ef67af18280a280f35b50346104b85760803660031901126104b85761102b612fa2565b7fb4467e799ded272c661fae9d93dddcd4288f2e4c2ea87d0d76147f78424d4a306060611056613007565b61105e612fd2565b9363ffffffff60ff6064359261107261337d565b1695868852600c6020526110958460408a209060ff801983541691151516179055565b868852600d602052604088208282168319825416179055868852600e60205282604089205560405193151584521660208301526040820152a280f35b50346104b85760203660031901126104b857604061012091600435815260056020522060ff60018060a01b038254169160018101549060028101546003820154906005600484015493015493604051968752602087015260408601526060850152608084015263ffffffff811660a0840152818160201c1660c0840152818160281c16151560e084015260301c161515610100820152f35b50346104b85760203660031901126104b85760ff604081611188612fa2565b16808452601060209081528285205491855260118152919093205460408051948552921615159083015290f35b50346104b85760203660031901126104b85760ff6040602092826111d7612fa2565b168152601184522054166040519015158152f35b50346104b85760203660031901126104b85760043561120861337d565b6112326040516112196040826130d0565b6006815265185b5bdd5b9d60d21b60208201528261346e565b61125e8130337f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b6136ae565b6040519081527fd53214ca07be5520e229c395f05a3e5c0697ec6279184ffbe2758d304fd322cc60203392a280f35b50346104b85760203660031901126104b8576004359067ffffffffffffffff82116104b857366023830112156104b85781600401359067ffffffffffffffff82116104b8573660248360051b850101116104b8576112e96133a3565b6112f16134d9565b808093815b848110156114845760248160051b83010135808452600560205260408420903360018060a01b03835416036114755760058201549060ff8260281c16611463575061134442610d7784613198565b908161135c575b5050426003909101556001016112f6565b60ff816020989394981c1686526004602052604086209060016040519261138284613083565b8054845201549163ffffffff83166020820152608060ff63ffffffff8560201c1694856040850152818160401c161515606085015260481c1615159101526004880154908115159182611458575b5060301c60ff16159081611450575b5080611447575b611402575b50600192916113f991613177565b9490915f61134b565b976114358361271061141b6113f9959c60019897613213565b049080821161143f575b8161142f91613244565b92613177565b98915091926113eb565b905080611425565b508015156113e6565b90505f6113df565b4210915060ff6113d0565b6321b5e5af60e01b8652600452602485fd5b6370d645e360e01b8552600485fd5b505091838261150d575b60209350806114d6575b5060405190828252838201527fd117f41d50ccfc0f62d15c908ef0c1f8aa8138e21bb22bcf6f9f60a147af440860403392a260018055604051908152f35b60405190815281848201527f4614a922d4b631d68d17e86a5b3e77c61f0e7ead56c4776dc95e0ef093bf95ad60403392a283611498565b826115166132da565b10610ed5576020935061154a83337f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b613497565b61148e565b50346104b85760a03660031901126104b857611569612fa2565b7fc84a9f1e745bce22ad9de1585ff0557730706c0f8be5271478de0c3a3b0672246080611594613007565b6044359363ffffffff6115a5612fe5565b60ff6115af612ff8565b936115b861337d565b169687895260136020526115db8560408b209060ff801983541691151516179055565b87895260176020528060408a2055878952601560205260408920838316841982541617905587895260166020526116218460408b209060ff801983541691151516179055565b6040519415158552602085015216604083015215156060820152a280f35b50346104b857806003193601126104b857546040516001600160a01b039091168152602090f35b50346104b857806003193601126104b8576003546040516001600160a01b039091168152602090f35b50346104b857806003193601126104b8576020600854604051908152f35b506101603660031901126104b8576004356116c6612fb2565b9160a43567ffffffffffffffff81116104df576116e790369060040161302c565b906116f0612fc2565b91610144359182151583036104ee576117076134d9565b6003546001600160a01b03169081611784575b50507f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b6001600160a01b031692915050813b156104c6576104808392839260405194858094819363d505accf60e01b83526101243590610104359060c4358d303360048901613299565b813b15611807576117ba928692839283604051809781958294630100553160e61b84526084356064356044353360048801613251565b03925af191826117ee575b50506117e8576117d9575b5f80808061171a565b630c7ae0a360e31b8252600482fd5b506117d0565b816117f8916130d0565b61180357835f6117c5565b8380fd5b8580fd5b50346104b857806003193601126104b85761182461337d565b61182c6134d9565b805460ff60a01b1916600160a01b1781556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602090a180f35b50346104b857806003193601126104b8576020600754604051908152f35b50346104b85760603660031901126104b8576118a4613016565b6024356044359160ff83168303611803576118bd6133a3565b6118c56134d9565b6002546001600160a01b03163303611a14576118ff6040516118e86040826130d0565b60048152633ab9b2b960e11b602082015282613b54565b6119296040516119106040826130d0565b6006815265185b5bdd5b9d60d21b60208201528361346e565b6119328361351f565b9361193c846135be565b61194684836135fe565b611950838561364a565b6040516370a0823160e01b81523060048201526020816024817f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b6001600160a01b03165afa9081156104bb5782916119de575b506119b084600754613177565b116119cf5760206119c3868686866136f2565b60018055604051908152f35b6335f6978b60e21b8152600490fd5b90506020813d602011611a0c575b816119f9602093836130d0565b81010312611a0857515f6119a3565b5f80fd5b3d91506119ec565b6318852ca560e11b8452600484fd5b50346104b85760203660031901126104b85760ff604060209282611a45612fa2565b168152601284522054166040519015158152f35b50346104b857806003193601126104b8576040517f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b6001600160a01b03168152602090f35b50346104b857806003193601126104b857611ab761337d565b80546001600160a01b03198116825581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346104b85760203660031901126104b85763ffffffff604060209260ff611b1e612fa2565b16815260148452205416604051908152f35b50346104b85760203660031901126104b857604060209160ff611b51612fa2565b168152600983522054604051908152f35b50346104b857806003193601126104b8576002546040516001600160a01b039091168152602090f35b50346104b85760403660031901126104b857611ba5613016565b6001600160a01b03168152600660205260408120805460243592908310156104b8576020611bd3848461305a565b90549060031b1c604051908152f35b50346104b857806003193601126104b85760ff6020915460a01c166040519015158152f35b50346104b85760203660031901126104b857604060209160ff611c28612fa2565b168152600e83522054604051908152f35b50346104b85760403660031901126104b857611c53613016565b60243590611c5f61337d565b611c676133a3565b611c6f6133f9565b6001600160a01b03908116907f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b168114611d1b57611cb46040516119106040826130d0565b7f0f51b71e5e9ee881072b57bf4022b60435e0000ad377b5c1434da39471002b5560207f00000000000000000000000098d7674011daea6c0cac896af80443b6b0200e3c611d03858286613497565b6040519485526001600160a01b031693a36001805580f35b63d667159760e01b8352600483fd5b50346104b85760203660031901126104b857600435611d476133a3565b80825260056020526040822080546001600160a01b03163303611e82576005810190815460ff8160281c16611e6e5760048201548015159081611e64575b5060ff8260301c169081611e5c575b5080611e4c575b611e38576001611dd8926501000000000060ff9360ff60281b19161785550192611dc88454600754613244565b6007555460201c16825490613a62565b611e048154337f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b613497565b546040519081527fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae059560203392a36001805580f35b633e2fa97b60e01b85526004849052602485fd5b5060ff60035460a01c1615611d9b565b90505f611d94565b905042105f611d85565b6321b5e5af60e01b85526004849052602485fd5b6370d645e360e01b8352600483fd5b50346104b85760203660031901126104b85760ff604060209282611eb3612fa2565b168152600c84522054166040519015158152f35b34611a085760c0366003190112611a0857600435611ee3612fb2565b9060a43567ffffffffffffffff8111611a0857611f0490369060040161302c565b9290611f0e6134d9565b611f38604051611f1f6040826130d0565b6006815265185b5bdd5b9d60d21b60208201528461346e565b6003546001600160a01b0316938415611fb757843b15611a0857611f7f945f9283604051809881958294630100553160e61b84526084356064356044353360048801613251565b03925af1918215611fac5760209361049b93611f9c575b506130f2565b5f611fa6916130d0565b5f611f96565b6040513d5f823e3d90fd5b635455514f60e01b5f5260045ffd5b34611a08576020366003190112611a085760ff611fe1612fa2565b165f52600b602052602060405f2054604051908152f35b34611a08575f366003190112611a085761201061337d565b6120186133f9565b60ff60a01b195f54165f557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a1005b34611a08576020366003190112611a085760ff61206a612fa2565b61207261337d565b16805f526004602052600160405f2001600160401b60ff60401b198254161790557ff78f5478f78ece65f53391387442d39e2760ea7455616d157657f461a0e517e95f80a2005b34611a08575f366003190112611a08576020604051620f42408152f35b34611a08576020366003190112611a08576004356120f26133a3565b6120fa6134d9565b5f81815260056020526040902080549091906001600160a01b031633036122f95760058201549060ff8260281c166122e75760ff8260201c165f52600460205260405f2060016040519161214d83613083565b8054835201549063ffffffff82166020820152608060ff604083019363ffffffff8160201c168552818160401c161515606085015260481c16151591015261219842610d7786613198565b92426003860155836121b4575b60208460018055604051908152f35b6004839501549081151591826122dc575b5060301c60ff161590816122d4575b50806122c4575b612260575b5050806121eb6132da565b106122515760209161221e82337f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b613497565b6040518281527f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a843392a38280806121a5565b636e2d286560e11b5f5260045ffd5b61227463ffffffff61271092511684613213565b04918083116122bc575b8261228891613244565b916040519081527f51dd30497f5f377d33b9478808ca4dab456aa7fbffb66ec8adef09a139592ad760203392a381836121e0565b91508161227e565b5063ffffffff81511615156121db565b9050856121d4565b4210915060ff6121c5565b6321b5e5af60e01b5f5260045260245ffd5b6370d645e360e01b5f5260045ffd5b34611a08576060366003190112611a08576080612323613016565b63ffffffff612330612fb2565b60ff81165f5260046020528161239a6123918360405f20966001604051986123578a613083565b80548a520154978960ff878b169a8b6020850152888160201c166040850152818160401c161515606085015260481c1615159101526138ca565b92604435613aa6565b9116906123b4836123ab8487613177565b92168092613177565b91620f424083116123d8575b60405194855260208501526040840152166060820152f35b620f424092506123c0565b34611a08576020366003190112611a08576004356123ff6133a3565b6124076134d9565b5f81815260056020526040902080546001600160a01b031633036122f957600581019081549160ff8360281c166126495760ff8360201c165f52600460205260405f209160016040519361245a85613083565b8054855201549263ffffffff84166020820152608060ff604083019563ffffffff8160201c168752818160401c161515606085015260481c1615159101526124a542610d7783613198565b935f936004830154801515908161263f575b5060ff8360301c16808091612638575b80612628575b6126155715908161260d575b50806125fd575b806125f4575b6125a7575b506001612515926501000000000060ff9360ff60281b19161785550192611dc88454600754613244565b7f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b61254282543383613497565b83612587575b505491604051928352602083015260408201527f94ffd6b85c71b847775c89ef6496b93cee961bdc6ff827fd117f174f06f745ae60603392a360018055005b836125906132da565b1061225157836125a1913390613497565b84612548565b60ff91959450612515926127106125c763ffffffff600194511688613213565b048681116125ed575b6125e281650100000000009298613244565b9793505092506124eb565b50856125d0565b508515156124e6565b5063ffffffff81511615156124e0565b9050886124d9565b88633e2fa97b60e01b5f5260045260245ffd5b5060ff60035460a01c16156124cd565b50816124c7565b90504210886124b7565b836321b5e5af60e01b5f5260045260245ffd5b34611a08576020366003190112611a085760ff612677612fa2565b165f526013602052602060ff60405f2054166040519015158152f35b34611a085760a0366003190112611a08576126ac612fa2565b7f699fa7f866be5cc1e82d7b656cc2621a932f59229af77660482cb772c24a66cc60806126d7613007565b6126df612fd2565b9363ffffffff6126ed612fe5565b8160ff6126f8612ff8565b9461270161337d565b1697885f5260136020526127248660405f209060ff801983541691151516179055565b885f52601460205260405f208282168319825416179055885f52601560205260405f208284168319825416179055885f5260166020526127738560405f209060ff801983541691151516179055565b604051951515865216602085015216604083015215156060820152a2005b34611a08576020366003190112611a085760ff6127ac612fa2565b6127b461337d565b16805f526004602052600160405f200160ff60401b1981541690557feaefa8d4750e7ddb7f90ca7d00bc6712996a0e1d7880878a7f4443f60b12941e5f80a2005b34611a08576020366003190112611a085760ff612810612fa2565b165f526016602052602060ff60405f2054166040519015158152f35b34611a08576020366003190112611a085760ff612847612fa2565b165f52600a602052602060405f2054604051908152f35b34611a08576020366003190112611a085760ff612879612fa2565b165f52600d602052602063ffffffff60405f205416604051908152f35b34611a08576040366003190112611a085760606128b1613016565b63ffffffff8061291b6128c2612fb2565b60ff81165f52600460205260405f20946001604051966128e188613083565b80548852015495608060ff86891698896020850152878160201c166040850152818160401c1615158b85015260481c1615159101526138ca565b166129268184613177565b90620f42408211612945575b6040519384526020840152166040820152f35b620f42409150612932565b34611a08576040366003190112611a0857612969612fa2565b7fe2bcc00690eab73769ac4b6a16a5aae08c82855fd488fcd96232b9f21f0d8a47602060ff612996613007565b9361299f61337d565b1692835f52601282526129c18160405f209060ff801983541691151516179055565b6040519015158152a2005b34611a08575f366003190112611a08576129e461337d565b600380546001600160a01b03191690555f7f188cb754c518e3db2a5a6f2c7e05e8924d9c600fdb7d70eb8a8e9a78cefe749a8180a2005b34611a08576060366003190112611a0857612a34612fa2565b602435906044358015158103611a085760ff7fb1ef9117b124c174ccab2ce3989bee1611d4e237c320a902ebf1db72abc9e2d092612a7061337d565b1692835f5260106020528060405f2055835f526011602052612aa18260405f209060ff801983541691151516179055565b60408051918252911515602082015290819081015b0390a2005b34611a08576040366003190112611a0857602061049b612ad9612fb2565b6004356130f2565b34611a08576040366003190112611a0857612afa612fa2565b6024359063ffffffff8216809203611a0857602060ff7fb02ac62f2bf80f694ec18bcd8af98c1703c1c37db5efaaaf422c2895da500a0c92612b3a61337d565b1692835f52600f825260405f208163ffffffff19825416179055604051908152a2005b34611a085760c0366003190112611a0857612b76612fa2565b60243590612b82612fd2565b612b8a612fe5565b92612b93612ff8565b9360a43580151595868203611a0857612baa61337d565b63ffffffff851692620f42408411612d145763ffffffff8116936127108511612cdc5760ff987f3b3175e1b9486521504d84a3af309d0efa648c74f06664f2759977852d637f4a98612ab69663ffffffff8060016040519e8f95612c0d87613083565b8d87526020870198895260408701958652608060608801978c1515895201978852169e8f5f52600460205260405f2090518155019551161663ffffffff198554161784555167ffffffff0000000084549160201b169067ffffffff00000000191617835551151560ff60401b83549160401b169060ff60401b191617825551151560ff60481b82549160481b169060ff60481b191617905560405195869586939095949160809363ffffffff809260a08801998852166020870152166040850152151560608401521515910152565b60405162461bcd60e51b815260206004820152601060248201526f0e0cadcc2d8e8f240e8dede40d0d2ced60831b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b0c2e0e440e8dede40d0d2ced60a31b6044820152606490fd5b34611a08576020366003190112611a085760a060ff612d65612fa2565b165f90815260136020908152604080832054601483528184205460178452828520546015855283862054601686529584902054845160ff9485161515815263ffffffff938416968101969096529385015293909316606083015290911615156080820152f35b34611a08576020366003190112611a085760ff612de6612fa2565b165f526017602052602060405f2054604051908152f35b34611a08575f366003190112611a085760206040516127108152f35b34611a08576020366003190112611a0857600435612e3561337d565b612e3d6133a3565b612e456133f9565b612e566040516112196040826130d0565b80612e5f6132da565b10612251577f2681c455422749afc6dceefd75dd0274b9b3cbf96e31023dc344731b78e7261f60207f00000000000000000000000098d7674011daea6c0cac896af80443b6b0200e3c612ed384827f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b613497565b6040519384526001600160a01b031692a260018055005b34611a08576040366003190112611a0857612f03612fa2565b60243590612f0f61337d565b81151580612f8a575b612f5a57602060ff7f7baa46cf0c4587615b98f7870e63472ae3d772624f6dc0dbe54f4672cab9f1d2921692835f52600a82528060405f2055604051908152a2005b60405163589956a560e11b81526020600482015260076024820152660706f6f6c4361760cc1b6044820152606490fd5b5060ff81165f52600960205260405f20548210612f18565b6004359060ff82168203611a0857565b6024359060ff82168203611a0857565b60e4359060ff82168203611a0857565b6044359063ffffffff82168203611a0857565b6064359063ffffffff82168203611a0857565b608435908115158203611a0857565b602435908115158203611a0857565b600435906001600160a01b0382168203611a0857565b9181601f84011215611a085782359167ffffffffffffffff8311611a085760208381860195010111611a0857565b805482101561306f575f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b60a0810190811067ffffffffffffffff82111761309f57604052565b634e487b7160e01b5f52604160045260245ffd5b610120810190811067ffffffffffffffff82111761309f57604052565b90601f8019910116810190811067ffffffffffffffff82111761309f57604052565b613170916130fe6133a3565b6131066134d9565b6131176040516119106040826130d0565b6131208161351f565b9161312a826135be565b61313482336135fe565b61313e818361364a565b61316a8130337f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b6136ae565b336136f2565b9060018055565b9190820180921161318457565b634e487b7160e01b5f52601160045260245ffd5b906040516131a5816130b3565b61010060ff6005839560018060a01b03815416855260018101546020860152600281015460408601526003810154606086015260048101546080860152015463ffffffff811660a0850152818160201c1660c0850152818160281c16151560e085015260301c161515910152565b8181029291811591840414171561318457565b8115613230570490565b634e487b7160e01b5f52601260045260245ffd5b9190820391821161318457565b9491928694919360c0979460018060a01b0316875260208701526040860152606085015260a060808501528160a0850152848401375f828201840152601f01601f1916010190565b9360c095919897969360ff9360e087019a60018060a01b0316875260018060a01b031660208701526040860152606085015216608083015260a08201520152565b6040516370a0823160e01b81523060048201526020816024817f000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b6001600160a01b03165afa908115611fac575f9161334b575b50600754808211156133455761334291613244565b90565b50505f90565b90506020813d602011613375575b81613366602093836130d0565b81010312611a0857515f61332d565b3d9150613359565b5f546001600160a01b0316330361339057565b63118cdaa760e01b5f523360045260245ffd5b6002600154146133b4576002600155565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60ff5f5460a01c161561340857565b60405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606490fd5b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b156134765750565b60405163589956a560e11b81529081906134939060048301613444565b0390fd5b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044808301939093529181526134d7916134d26064836130d0565b613c99565b565b60ff5f5460a01c166134e757565b60405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606490fd5b60ff905f608060405161353181613083565b82815282602082015282604082015282606082015201521690815f52600460205260405f209160016040519361356685613083565b8054855201549263ffffffff8416602082015263ffffffff8460201c16604082015260ff808560401c1615948515606084015260481c1615156080820152926135ac5750565b63788ff61160e11b5f5260045260245ffd5b60ff16805f52601060205260405f205480159081156135f3575b50156135e15750565b63ed2bea4b60e01b5f5260045260245ffd5b90504211155f6135d8565b9060ff1690815f52600b60205260405f20549081156136455761362090613c1c565b9181831061362d57505050565b63a3d470c360e01b5f5260045260245260445260645ffd5b505050565b60ff16805f52600a60205260405f20548061367b575b505f52600960205261367760405f20918254613177565b9055565b815f526009602052806136928460405f2054613177565b1115613660579063db914f1b60e01b5f5260045260245260445ffd5b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526134d7916134d26084836130d0565b60085492949390915f19841461318457600184016008558395613716828286613b82565b9085845180155f146138b8575060805f955b015115159163ffffffff806005604051996137428b6130b3565b60018060a01b0316998a81526020810199898b52604082014281526060830190428252608084019283528560a085019b168b5260ff60c0850198169c8d895260e08501995f8b5261010086019b8c525f528560205260405f209460018060a01b039051166bffffffffffffffffffffffff60a01b865416178555516001850155516002840155516003830155516004820155019551161663ffffffff198554161784555164ff0000000084549160201b169064ff00000000191617835551151560ff60281b83549160281b169060ff60281b191617825551151566ff00000000000082549160301b169066ff0000000000001916179055825f52600660205260405f2091825491600160401b83101561309f57613888837fbde7f0ba1630d25515c7ab99ba47d5640b7ffb4c673b2a5464ae67919558929895600160409601815561305a565b81549060031b9088821b915f19901b19161790556138a881600754613177565b60075582519182526020820152a3565b6138c460809142613177565b95613728565b9060ff1690815f52600c60205260ff60405f2054161561334557815f52600e60205260405f2054908115613979576139269161390861390d92613c1c565b613226565b825f52600d60205263ffffffff60405f20541690613213565b905f52600f60205263ffffffff60405f20541680151580613970575b613968575b5063ffffffff811161395d575b63ffffffff1690565b5063ffffffff613954565b90505f613947565b50808211613942565b5050505f90565b9060e082015115801590613a54575b61334557608082015180613a3f57505b8060c0830160ff8151165f52601160205260ff60405f205416613a03575b505060608201519182821115613979576139fa6139e364496cebb800946139ff94613244565b9163ffffffff60a060208301519201511690613213565b613213565b0490565b60ff9051165f52601060205260405f205490818015159182613a35575b5050613a2d575b806139bd565b90505f613a27565b119050815f613a20565b80821015613a4d575061399f565b905061399f565b50606082015181111561398f565b60ff1690815f52600960205260405f2054818110613a935790613a8491613244565b905f52600960205260405f2055565b8263218a315960e01b5f5260045260245ffd5b9060ff16805f52601360205260ff60405f205416158015613b4c575b61334557805f52601560205263ffffffff60405f20541691815f52601760205260405f2054918215155f14613b1f575090613afc91613226565b905b8015158061397057613968575063ffffffff811161395d5763ffffffff1690565b613b4692505f526014602052670de0b6b3a764000063ffffffff60405f2054169104613213565b90613afe565b508115613ac2565b6001600160a01b031615613b655750565b60405163eac0d38960e01b81529081906134939060048301613444565b613bf2613bff9392613bf963ffffffff9360ff83165f52600460205284613bf28460405f2093600160405195613bb787613083565b80548752015494608060ff86881697886020850152878160201c166040850152818160401c161515606085015260481c1615159101526138ca565b1690613177565b93613aa6565b620f42408111613c125763ffffffff1690565b50620f4240613954565b6003546001600160a01b03169081156133455760405163db74559b60e01b81526001600160a01b03909116600482015290602090829060249082905afa908115611fac575f91613c6a575090565b90506020813d602011613c91575b81613c85602093836130d0565b81010312611a08575190565b3d9150613c78565b905f602091828151910182855af115611fac575f513d613ce857506001600160a01b0381163b155b613cc85750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415613cc156fea26469706673582212201250440bd948a4b35dfab8babb6cbec4f04363b14c63ee369a1b4f419f5f58c964736f6c634300081e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b00000000000000000000000098d7674011daea6c0cac896af80443b6b0200e3c
-----Decoded View---------------
Arg [0] : _token (address): 0xBb0E53741f2D1ebFb87F6a89632242F58A08f13B
Arg [1] : _rewardTreasury (address): 0x98d7674011DAeA6c0cAc896aF80443B6b0200E3c
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b
Arg [1] : 00000000000000000000000098d7674011daea6c0cac896af80443b6b0200e3c
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.