编译器
0.8.26+commit.8a97fa7a
文件 1 的 12:Address.sol
pragma solidity ^0.8.20;
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success,) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(address target, bool success, bytes memory returndata)
internal
view
returns (bytes memory)
{
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
文件 2 的 12:Context.sol
pragma solidity ^0.8.20;
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;
}
}
文件 3 的 12:Element369HolderVault.sol
pragma solidity ^0.8.26;
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "./interfaces/IElement369NFT.sol";
import "./lib/constants.sol";
import "./lib/Time.sol";
contract Element369HolderVault is Ownable2Step {
using SafeERC20 for IERC20;
struct Cycle {
bool initialized;
uint256 infernoPerMulitplier;
uint256 fluxPerMultiplier;
uint256 e280PerMultiplier;
}
struct Cycle777 {
uint32 startCycleId;
uint32 endCycleId;
uint256 multiplierPool;
uint256 infernoPool;
uint256 e280Pool;
}
address public immutable E369_NFT;
address public FluxHub;
address public devWallet;
mapping(address token => uint256) public totalTokenPool;
mapping(address token => uint256) public totalTokenPaid;
uint256 public minCyclePool;
uint32 public lastUpdatedCycle;
mapping(uint256 id => Cycle) public cycles;
mapping(uint256 id => Cycle777) public cycles777;
mapping(uint256 tokenId => mapping(address token => uint256)) public cycle777AmountClaimed;
mapping(uint256 tokenId => mapping(address token => uint256)) public cycle777BackingClaimed;
mapping(uint256 tokenId => uint32) public nftLastClaim;
mapping(uint256 tokenId => uint32) public nftLastBacking;
error Unauthorized();
error ZeroInput();
error ZeroAddress();
error NoAllocation();
error CycleCooldown();
error NoCyclesAvailable();
error TokenExists();
error Prohibited();
event CycleUpdated();
constructor(address _owner, address _E369_NFT, address _devWallet, uint256 _minCyclePool) Ownable(_owner) {
if (_owner == address(0)) revert ZeroAddress();
if (_E369_NFT == address(0)) revert ZeroAddress();
if (_devWallet == address(0)) revert ZeroAddress();
if (_minCyclePool == 0) revert ZeroInput();
E369_NFT = _E369_NFT;
devWallet = _devWallet;
minCyclePool = _minCyclePool;
uint32 initalCycle = (((MINT_START_DATE - FLUX_START_DATE) / 86400) + 1) / 11 - 1;
cycles[initalCycle].initialized = true;
lastUpdatedCycle = initalCycle;
for (uint32 i = 0; i < MAX_777_CYCLES_NUMBER; i++) {
uint32 startCycle = _getStartCycleForCycle777(i);
uint32 endCycle = _getEndCycleForCycle777(i);
cycles777[i] = Cycle777(startCycle, endCycle, 0, 0, 0);
}
}
function updateCycle() external {
uint32 finalizedCycle = getCurrentE369Cycle() - 1;
if (finalizedCycle <= lastUpdatedCycle) revert CycleCooldown();
_checkCycleCreationDay(finalizedCycle);
(uint256 infernoPool, uint256 fluxPool, uint256 e280Pool) = _getNextCyclePools();
uint256 totalMultipliers = IElement369NFT(E369_NFT).multiplierPool();
uint256 infernoShare = _processTokenPool(INFERNO, infernoPool, totalMultipliers);
uint256 fluxShare;
if (fluxPool > 0) {
fluxShare = _processTokenPool(FLUX, fluxPool, totalMultipliers);
}
uint256 e280Share = _processTokenPool(E280, e280Pool, totalMultipliers);
cycles[finalizedCycle] = Cycle(true, infernoShare, fluxShare, e280Share);
lastUpdatedCycle = finalizedCycle;
emit CycleUpdated();
}
function claimRewards(uint256[] calldata tokenIds) external {
if (tokenIds.length == 0) revert ZeroInput();
uint256[] memory nftData = IElement369NFT(E369_NFT).batchGetPackedTokenData(tokenIds, msg.sender);
uint256 totalInferno;
uint256 totalFlux;
uint256 totalE280;
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
uint256 tokenData = nftData[i];
uint32 nftMintCycle = _getMintCycle(tokenData);
uint32 nftBurnCycle = _getBurnCycle(tokenData);
uint32 lastCycle = nftBurnCycle > 0 ? nftBurnCycle : lastUpdatedCycle + 1;
uint16 nftMultiplier = _getMultiplier(tokenData);
uint32 nftLastClaimed = nftLastClaim[tokenId];
(uint32 endCycle, uint256 infernoPool, uint256 fluxPool, uint256 e280Pool) =
_processCycles(nftMintCycle, nftMultiplier, nftLastClaimed, lastCycle);
totalInferno += infernoPool;
totalFlux += fluxPool;
totalE280 += e280Pool;
nftLastClaim[tokenId] = endCycle;
}
_processTokenRewardsPayout(INFERNO, msg.sender, totalInferno);
_processTokenRewardsPayout(FLUX, msg.sender, totalFlux);
_processTokenRewardsPayout(E280, msg.sender, totalE280);
}
function claim777Rewards(uint256[] calldata tokenIds) external {
if (tokenIds.length == 0) revert ZeroInput();
uint32 currentCycle777 = getCurrentCycle777();
if (currentCycle777 == 0) revert NoCyclesAvailable();
uint32 currentCycle = getCurrentE369Cycle();
uint256 totalInferno;
uint256 totalE280;
uint256[] memory nftData = IElement369NFT(E369_NFT).batchGetPackedTokenData(tokenIds, msg.sender);
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenData = nftData[i];
uint32 nftMintCycle = _getMintCycle(tokenData);
uint32 nftBurnCycle = _getBurnCycle(tokenData);
uint32 lastCycle = nftBurnCycle > 0 ? nftBurnCycle : currentCycle;
uint16 nftMultiplier = _getMultiplier(tokenData);
(uint256 infernoPool, uint256 e280Pool) =
_processTokenIdCycles777(tokenIds[i], nftMultiplier, nftMintCycle, lastCycle, currentCycle777);
totalInferno += infernoPool;
totalE280 += e280Pool;
}
_processTokenRewardsPayout(INFERNO, msg.sender, totalInferno);
_processTokenRewardsPayout(E280, msg.sender, totalE280);
}
function claimBacking(uint256[] calldata tokenIds) external {
if (tokenIds.length == 0) revert ZeroInput();
uint256[] memory nftData = IElement369NFT(E369_NFT).batchGetPackedTokenData(tokenIds, msg.sender);
uint256 totalInferno;
uint256 totalFlux;
uint256 totalE280;
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
uint256 tokenData = nftData[i];
uint32 nftMintCycle = _getMintCycle(tokenData);
uint32 nftBurnCycle = _getBurnCycle(tokenData);
if (nftBurnCycle == 0) revert TokenExists();
uint16 nftMultiplier = _getMultiplier(tokenData);
uint32 lastClaimed = nftLastBacking[tokenId];
(uint32 endCycle, uint256 infernoPool, uint256 fluxPool, uint256 e280Pool) =
_processCycles(nftMintCycle, nftMultiplier, lastClaimed, nftBurnCycle);
totalInferno += infernoPool;
totalFlux += fluxPool;
totalE280 += e280Pool;
nftLastBacking[tokenId] = endCycle;
}
_processTokenBackingPayout(INFERNO, msg.sender, totalInferno);
_processTokenBackingPayout(FLUX, msg.sender, totalFlux);
_processTokenBackingPayout(E280, msg.sender, totalE280);
}
function claim777Backing(uint256[] calldata tokenIds) external {
if (tokenIds.length == 0) revert ZeroInput();
uint32 currentCycle777 = getCurrentCycle777();
if (currentCycle777 == 0) revert NoCyclesAvailable();
uint256[] memory nftData = IElement369NFT(E369_NFT).batchGetPackedTokenData(tokenIds, msg.sender);
uint256 totalInferno;
uint256 totalE280;
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenData = nftData[i];
uint32 nftMintCycle = _getMintCycle(tokenData);
uint32 nftBurnCycle = _getBurnCycle(tokenData);
if (nftBurnCycle == 0) revert TokenExists();
uint16 nftMultiplier = _getMultiplier(tokenData);
(uint256 infernoPool, uint256 e280Pool) =
_processTokenIdBacking777(tokenIds[i], nftMultiplier, nftMintCycle, nftBurnCycle, currentCycle777);
totalInferno += infernoPool;
totalE280 += e280Pool;
}
_processTokenBackingPayout(INFERNO, msg.sender, totalInferno);
_processTokenBackingPayout(E280, msg.sender, totalE280);
}
function register777CycleTokens(uint256 infernoAmount, uint256 e280Amount) external {
if (msg.sender != FluxHub) revert Unauthorized();
uint32 currentCycleId = getCurrentCycle777() - 1;
Cycle777 storage current = cycles777[currentCycleId];
current.infernoPool += infernoAmount;
current.e280Pool += e280Amount;
totalTokenPool[INFERNO] += infernoAmount;
totalTokenPool[E280] += e280Amount;
}
function updateStoredMultipliers(uint32 cycleId, uint256 totalMultipliers) external {
if (msg.sender != E369_NFT) revert Unauthorized();
if (cycles777[cycleId].multiplierPool != 0) return;
cycles777[cycleId].multiplierPool = totalMultipliers;
}
function updateStoredMultipliersOnBurn(uint32 cycleId, uint256 totalMultipliers, uint256 multiplierDeduction)
external
{
if (msg.sender != E369_NFT) revert Unauthorized();
Cycle777 storage current = cycles777[cycleId];
if (current.multiplierPool == 0) {
current.multiplierPool = totalMultipliers;
} else {
current.multiplierPool -= multiplierDeduction;
}
}
function setMinCyclePool(uint256 limit) external onlyOwner {
minCyclePool = limit;
}
function setFluxHub(address fluxHub) external {
if (msg.sender != E369_NFT) revert Unauthorized();
FluxHub = fluxHub;
}
function getCurrentE369Cycle() public view returns (uint32) {
uint32 daysPassed = Time.daysSince(FLUX_START_DATE) + 1;
return daysPassed / E369_CYCLE_INTERVAL;
}
function getRewards(uint256[] calldata tokenIds, address account, bool isBacking)
external
view
returns (
bool[] memory availability,
bool[] memory burned,
uint256 infernoPool,
uint256 fluxPool,
uint256 e280Pool
)
{
if (tokenIds.length == 0) revert ZeroInput();
availability = new bool[](tokenIds.length);
burned = new bool[](tokenIds.length);
uint256[] memory nftData = IElement369NFT(E369_NFT).batchGetPackedTokenData(tokenIds, account);
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
uint256 tokenData = nftData[i];
uint32 nftMintCycle = _getMintCycle(tokenData);
uint32 nftBurnCycle = _getBurnCycle(tokenData);
uint16 nftMultiplier = _getMultiplier(tokenData);
bool isBurned = nftBurnCycle > 0;
burned[i] = isBurned;
uint32 nftLastClaimed = isBacking ? nftLastBacking[tokenId] : nftLastClaim[tokenId];
uint32 startCycle = nftLastClaimed == 0 ? nftMintCycle : nftLastClaimed;
uint32 lastCycle = isBurned ? nftBurnCycle : lastUpdatedCycle + 1;
bool available = startCycle < lastCycle;
availability[i] = isBacking ? available && isBurned : available;
if (available) {
uint256 endCycle = _applyMaxCycleProtection(startCycle, lastCycle);
uint256 infernoPerNFt;
uint256 fluxPerNFt;
uint256 e280PerNFt;
unchecked {
for (uint256 j = startCycle; j < endCycle; j++) {
infernoPerNFt += cycles[j].infernoPerMulitplier;
fluxPerNFt += cycles[j].fluxPerMultiplier;
e280PerNFt += cycles[j].e280PerMultiplier;
}
infernoPool += (infernoPerNFt * nftMultiplier) / 1e18;
fluxPool += (fluxPerNFt * nftMultiplier) / 1e18;
e280Pool += (e280PerNFt * nftMultiplier) / 1e18;
}
}
}
}
function get777Rewards(uint256[] calldata tokenIds, address account, bool isBacking)
external
view
returns (bool[] memory availability, bool[] memory burned, uint256 infernoPool, uint256 e280Pool)
{
if (tokenIds.length == 0) revert ZeroInput();
availability = new bool[](tokenIds.length);
burned = new bool[](tokenIds.length);
IElement369NFT nft = IElement369NFT(E369_NFT);
uint32 currentCycle = getCurrentE369Cycle();
uint256[] memory nftData = nft.batchGetPackedTokenData(tokenIds, account);
uint32 currentCycle777 = getCurrentCycle777();
if (currentCycle777 < 1) return (availability, burned, 0, 0);
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
uint256 tokenData = nftData[i];
uint32 nftMintCycle = _getMintCycle(tokenData);
uint32 nftBurnCycle = _getBurnCycle(tokenData);
uint16 nftMultiplier = _getMultiplier(tokenData);
bool isBurned = nftBurnCycle > 0;
burned[i] = isBurned;
uint32 endCycle = isBurned ? nftBurnCycle : currentCycle;
uint256 infernoPerNFt;
uint256 e280PerNFt;
mapping(address => uint256) storage previousClaim =
isBacking ? cycle777BackingClaimed[tokenId] : cycle777AmountClaimed[tokenId];
uint256 nftClaimedInferno = previousClaim[INFERNO];
uint256 nftClaimedE280 = previousClaim[E280];
for (uint256 j = 0; j < currentCycle777; j++) {
Cycle777 memory cycle = cycles777[j];
if (cycle.multiplierPool == 0 || endCycle < cycle.endCycleId) break;
if (nftMintCycle > cycle.startCycleId) continue;
infernoPerNFt += calculateCycle777Share(cycle.infernoPool, cycle.multiplierPool);
e280PerNFt += calculateCycle777Share(cycle.e280Pool, cycle.multiplierPool);
}
infernoPerNFt = (infernoPerNFt * nftMultiplier) / 1e18;
e280PerNFt = (e280PerNFt * nftMultiplier) / 1e18;
bool available = infernoPerNFt > nftClaimedInferno && e280PerNFt > nftClaimedE280;
availability[i] = isBacking ? available && isBurned : available;
if (available) {
infernoPool += infernoPerNFt - nftClaimedInferno;
e280Pool += e280PerNFt - nftClaimedE280;
}
}
}
function getNextCyclePools() public view returns (uint256 infernoPool, uint256 fluxPool, uint256 e280Pool) {
infernoPool = IERC20(INFERNO).balanceOf(address(this)) + totalTokenPaid[INFERNO] - totalTokenPool[INFERNO];
fluxPool = IERC20(FLUX).balanceOf(address(this)) + totalTokenPaid[FLUX] - totalTokenPool[FLUX];
e280Pool = IERC20(E280).balanceOf(address(this)) + totalTokenPaid[E280] - totalTokenPool[E280];
}
function getCurrentCycle777() public view returns (uint32) {
uint32 daysPassed = Time.daysSince(FLUX_START_DATE) + 1;
uint32 totalCycles = daysPassed / CYCLE_777_DAYS;
return totalCycles > MAX_777_CYCLES_NUMBER ? MAX_777_CYCLES_NUMBER : totalCycles;
}
function _checkCycleCreationDay(uint32 cycleId) internal view {
uint32 maxDay = (cycleId + 1) * E369_CYCLE_INTERVAL + CYCLE_CREATION_OFFSET;
uint32 daysPassed = Time.daysSince(FLUX_START_DATE) + 1;
if (daysPassed > maxDay) revert Prohibited();
}
function _getNextCyclePools() internal view returns (uint256 infernoPool, uint256 fluxPool, uint256 e280Pool) {
infernoPool = _getNextCyclePool(INFERNO);
fluxPool = _getNextCyclePool(FLUX);
e280Pool = _getNextCyclePool(E280);
}
function _getNextCyclePool(address token) public view returns (uint256) {
uint256 pool = IERC20(token).balanceOf(address(this)) + totalTokenPaid[token] - totalTokenPool[token];
if (pool < minCyclePool) {
if (token == FLUX) return 0;
revert NoAllocation();
}
return pool;
}
function _processTokenPool(address token, uint256 amount, uint256 totalMultipliers)
internal
returns (uint256 share)
{
share = (amount * 1e18) / (totalMultipliers * 2);
totalTokenPool[token] += amount;
}
function _processTokenRewardsPayout(address token, address account, uint256 amount) internal {
totalTokenPaid[token] += amount;
IERC20(token).safeTransfer(account, amount);
}
function _processTokenBackingPayout(address token, address account, uint256 amount) internal {
totalTokenPaid[token] += amount;
uint256 devFee = amount / PERCENTAGE_BASE;
uint256 totalFee = amount * BACKING_CLAIM_TAX / PERCENTAGE_BASE;
IERC20(token).safeTransfer(devWallet, devFee);
IERC20(token).safeTransfer(account, amount - totalFee);
}
function _processCycles(uint32 nftMintCycle, uint16 nftMultiplier, uint32 lastClaim, uint32 maxCycle)
internal
view
returns (uint32 endCycle, uint256 infernoPool, uint256 fluxPool, uint256 e280Pool)
{
uint32 startCycle = lastClaim == 0 ? nftMintCycle : lastClaim;
if (startCycle == maxCycle) revert NoCyclesAvailable();
endCycle = _applyMaxCycleProtection(startCycle, maxCycle);
unchecked {
for (uint256 i = startCycle; i < endCycle; i++) {
Cycle memory cycle = cycles[i];
if (!cycle.initialized) continue;
infernoPool += cycle.infernoPerMulitplier;
fluxPool += cycle.fluxPerMultiplier;
e280Pool += cycle.e280PerMultiplier;
}
}
infernoPool = (infernoPool * nftMultiplier) / 1e18;
fluxPool = (fluxPool * nftMultiplier) / 1e18;
e280Pool = (e280Pool * nftMultiplier) / 1e18;
}
function _processTokenIdCycles777(
uint256 tokenId,
uint16 nftMultiplier,
uint256 nftMintCycle,
uint256 lastCycle,
uint32 totalCycles
) internal returns (uint256 infernoPool, uint256 e280Pool) {
uint256 nftClaimedInferno = cycle777AmountClaimed[tokenId][INFERNO];
uint256 nftClaimedE280 = cycle777AmountClaimed[tokenId][E280];
for (uint256 i = 0; i < totalCycles; i++) {
Cycle777 memory cycle = cycles777[i];
if (cycle.multiplierPool == 0 || lastCycle < cycle.endCycleId) break;
if (nftMintCycle > cycle.startCycleId) continue;
infernoPool += calculateCycle777Share(cycle.infernoPool, cycle.multiplierPool);
e280Pool += calculateCycle777Share(cycle.e280Pool, cycle.multiplierPool);
}
infernoPool = (infernoPool * nftMultiplier) / 1e18;
e280Pool = (e280Pool * nftMultiplier) / 1e18;
if (infernoPool == nftClaimedInferno || e280Pool == nftClaimedE280) revert NoAllocation();
cycle777AmountClaimed[tokenId][INFERNO] = infernoPool;
cycle777AmountClaimed[tokenId][E280] = e280Pool;
infernoPool -= nftClaimedInferno;
e280Pool -= nftClaimedE280;
}
function _processTokenIdBacking777(
uint256 tokenId,
uint16 nftMultiplier,
uint256 nftMintCycle,
uint256 lastCycle,
uint32 totalCycles
) internal returns (uint256 infernoPool, uint256 e280Pool) {
uint256 nftClaimedInferno = cycle777BackingClaimed[tokenId][INFERNO];
uint256 nftClaimedE280 = cycle777BackingClaimed[tokenId][E280];
for (uint256 i = 0; i < totalCycles; i++) {
Cycle777 memory cycle = cycles777[i];
if (cycle.multiplierPool == 0 || lastCycle < cycle.endCycleId) break;
if (nftMintCycle > cycle.startCycleId) continue;
infernoPool += calculateCycle777Share(cycle.infernoPool, cycle.multiplierPool);
e280Pool += calculateCycle777Share(cycle.e280Pool, cycle.multiplierPool);
}
infernoPool = (infernoPool * nftMultiplier) / 1e18;
e280Pool = (e280Pool * nftMultiplier) / 1e18;
if (infernoPool == nftClaimedInferno || e280Pool == nftClaimedE280) revert NoAllocation();
cycle777BackingClaimed[tokenId][INFERNO] = infernoPool;
cycle777BackingClaimed[tokenId][E280] = e280Pool;
infernoPool -= nftClaimedInferno;
e280Pool -= nftClaimedE280;
}
function calculateCycle777Share(uint256 amount, uint256 multipliers) internal pure returns (uint256) {
return (amount * 1e18) / (multipliers * 2);
}
function _applyMaxCycleProtection(uint32 startCycle, uint32 currentCycle) internal pure returns (uint32) {
uint32 maxEndCycle = startCycle + MAX_CYCLES_PER_CLAIM;
return currentCycle < maxEndCycle ? currentCycle : maxEndCycle;
}
function _getNftTier(uint256 packedData) internal pure returns (uint8) {
return uint8(packedData & BITMASK_NFT_TIER);
}
function _getMultiplier(uint256 packedData) internal pure returns (uint16) {
return uint16((packedData >> BITPOS_MULTIPLIER) & BITMASK_MULTIPLIER);
}
function _getMintCycle(uint256 packedData) internal pure returns (uint32) {
return uint32((packedData >> BITPOS_MINT_CYCLE) & BITMASK_MINT_CYCLE);
}
function _getBurnCycle(uint256 packedData) internal pure returns (uint32) {
return uint32((packedData >> BITPOS_BURN_CYCLE) & BITMASK_BURN_CYCLE);
}
function _getBurnAddress(uint256 packedData) internal pure returns (address) {
return address(uint160((packedData >> BITPOS_BURN_ADDRESS) & BITMASK_BURN_ADDRESS));
}
function _getStartCycleForCycle777(uint32 cycle777Id) public pure returns (uint32) {
return ((CYCLE_777_DAYS * cycle777Id) + CYCLE_777_DAYS / 2) / E369_CYCLE_INTERVAL - 1;
}
function _getEndCycleForCycle777(uint32 cycle777Id) public pure returns (uint32) {
return ((CYCLE_777_DAYS * (cycle777Id + 1)) / E369_CYCLE_INTERVAL);
}
}
文件 4 的 12:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 5 的 12:IERC20Permit.sol
pragma solidity ^0.8.20;
interface IERC20Permit {
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 6 的 12:IElement369NFT.sol
pragma solidity ^0.8.24;
interface IElement369NFT {
function multiplierPool() external view returns (uint256);
function batchGetPackedTokenData(uint256[] memory tokenIds, address account)
external
view
returns (uint256[] memory data);
}
文件 7 的 12:ITitanOnBurn.sol
pragma solidity ^0.8.10;
interface ITitanOnBurn {
function onBurn(address user, uint256 amount) external;
}
文件 8 的 12:Ownable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 9 的 12:Ownable2Step.sol
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}
文件 10 的 12:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
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);
}
}
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);
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
文件 11 的 12:Time.sol
pragma solidity 0.8.26;
library Time {
function blockTs() internal view returns (uint32 ts) {
assembly {
ts := timestamp()
}
}
function dayCountByT(uint32 t) internal pure returns (uint32 dayCount) {
assembly {
let adjustedTime := sub(t, 61200)
dayCount := div(adjustedTime, 86400)
}
}
function weekSince(uint32 t) internal view returns (uint32 weeksPassed) {
assembly {
let currentTime := timestamp()
let timeElapsed := sub(currentTime, t)
weeksPassed := div(timeElapsed, 604800)
}
}
function daysSince(uint32 t) public view returns (uint32 daysPassed) {
assembly {
let currentTime := timestamp()
daysPassed := div(sub(currentTime, t), 86400)
}
}
}
文件 12 的 12:constants.sol
pragma solidity ^0.8.24;
import "../interfaces/ITitanOnBurn.sol";
import "@openzeppelin/contracts/interfaces/IERC20.sol";
address constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address constant TITANX = 0xF19308F923582A6f7c465e5CE7a9Dc1BEC6665B1;
address constant FLUX = 0xBFDE5ac4f5Adb419A931a5bF64B0f3BB5a623d06;
address constant FLUX_STAKING = 0xd605a87187563C94c577a6E57e4a36eC8433B9aE;
address constant FLUX_AUCTIONS = 0x36e5a8105f000029d4B3B99d0C3D0e24aaA52adF;
address constant HELIOS = 0x2614f29C39dE46468A921Fd0b41fdd99A01f2EDf;
address constant INFERNO = 0x00F116ac0c304C570daAA68FA6c30a86A04B5C5F;
address constant E280 = 0xe9A53C43a0B58706e67341C4055de861e29Ee943;
address constant TITANX_WETH_POOL = 0xc45A81BC23A64eA556ab4CdF08A86B61cdcEEA8b;
address constant TITANX_INFERNO_POOL = 0x1E90B67149e688DfB95fD73Acacd8ADefd16d88D;
address constant TITANX_HELIOS_POOL = 0x2C83C54C5612BfD62a78124D4A0eA001278a689c;
uint32 constant FLUX_START_DATE = 1727024400;
uint32 constant MINT_START_DATE = FLUX_START_DATE + 60 days;
uint32 constant ELEMENT_END_DATE = FLUX_START_DATE + 2331 days;
uint32 constant MINT_CYCLE_LENGTH = 44;
uint8 constant DEV_PERCENT = 8;
uint256 constant BITPOS_NFT_TIER = 0;
uint256 constant BITMASK_NFT_TIER = (1 << 8) - 1;
uint256 constant BITPOS_MULTIPLIER = 8;
uint256 constant BITMASK_MULTIPLIER = (1 << 16) - 1;
uint256 constant BITPOS_MINT_CYCLE = 24;
uint256 constant BITMASK_MINT_CYCLE = (1 << 32) - 1;
uint256 constant BITPOS_BURN_CYCLE = 56;
uint256 constant BITMASK_BURN_CYCLE = (1 << 32) - 1;
uint256 constant BITPOS_BURN_ADDRESS = 88;
uint256 constant BITMASK_BURN_ADDRESS = (1 << 160) - 1;
uint32 constant MAX_DURATION = 2888 days;
uint32 constant MAX_STAKES_PER_CLAIM = 100;
uint32 constant TREASURY_PERCENTS = 70;
uint32 constant DAY_777_OFFSET = 3;
uint32 constant INFERNO_SWAP_PERCENTAGE = 42;
uint32 constant BURN_PERCENTAGE = 16;
uint32 constant INCENTIVE_FEE_BASE = 100_000;
uint32 constant BPS_BASE = 10_000;
uint32 constant PERCENTAGE_BASE = 100;
uint32 constant CYCLE_CREATION_OFFSET = 2;
uint32 constant MAX_777_CYCLES_NUMBER = 4;
uint32 constant CYCLE_777_DAYS = 777;
uint32 constant E369_CYCLE_INTERVAL = 11;
uint16 constant MAX_CYCLES_PER_CLAIM = 100;
uint8 constant BACKING_CLAIM_TAX = 3;
address constant UNISWAP_V2_FACTORY = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
address constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address constant UNISWAP_V3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
uint24 constant POOL_FEE_1PERCENT = 10000;
bytes4 constant INTERFACE_ID_ERC165 = 0x01ffc9a7;
bytes4 constant INTERFACE_ID_ERC20 = type(IERC20).interfaceId;
bytes4 constant INTERFACE_ID_ERC721 = 0x80ac58cd;
bytes4 constant INTERFACE_ID_ERC721Metadata = 0x5b5e139f;
bytes4 constant INTERFACE_ID_ITITANONBURN = type(ITitanOnBurn).interfaceId;
{
"compilationTarget": {
"contracts/Element369HolderVault.sol": "Element369HolderVault"
},
"evmVersion": "paris",
"libraries": {
"contracts/lib/Time.sol:Time": "0xbbf25ca275325ef4682851a12bd8e9aa714da2f4"
},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_E369_NFT","type":"address"},{"internalType":"address","name":"_devWallet","type":"address"},{"internalType":"uint256","name":"_minCyclePool","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"CycleCooldown","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"NoAllocation","type":"error"},{"inputs":[],"name":"NoCyclesAvailable","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":[],"name":"Prohibited","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TokenExists","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroInput","type":"error"},{"anonymous":false,"inputs":[],"name":"CycleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","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"},{"inputs":[],"name":"E369_NFT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FluxHub","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"cycle777Id","type":"uint32"}],"name":"_getEndCycleForCycle777","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"_getNextCyclePool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"cycle777Id","type":"uint32"}],"name":"_getStartCycleForCycle777","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"claim777Backing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"claim777Rewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"claimBacking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"token","type":"address"}],"name":"cycle777AmountClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"token","type":"address"}],"name":"cycle777BackingClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cycles","outputs":[{"internalType":"bool","name":"initialized","type":"bool"},{"internalType":"uint256","name":"infernoPerMulitplier","type":"uint256"},{"internalType":"uint256","name":"fluxPerMultiplier","type":"uint256"},{"internalType":"uint256","name":"e280PerMultiplier","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cycles777","outputs":[{"internalType":"uint32","name":"startCycleId","type":"uint32"},{"internalType":"uint32","name":"endCycleId","type":"uint32"},{"internalType":"uint256","name":"multiplierPool","type":"uint256"},{"internalType":"uint256","name":"infernoPool","type":"uint256"},{"internalType":"uint256","name":"e280Pool","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"devWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"isBacking","type":"bool"}],"name":"get777Rewards","outputs":[{"internalType":"bool[]","name":"availability","type":"bool[]"},{"internalType":"bool[]","name":"burned","type":"bool[]"},{"internalType":"uint256","name":"infernoPool","type":"uint256"},{"internalType":"uint256","name":"e280Pool","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentCycle777","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentE369Cycle","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNextCyclePools","outputs":[{"internalType":"uint256","name":"infernoPool","type":"uint256"},{"internalType":"uint256","name":"fluxPool","type":"uint256"},{"internalType":"uint256","name":"e280Pool","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"isBacking","type":"bool"}],"name":"getRewards","outputs":[{"internalType":"bool[]","name":"availability","type":"bool[]"},{"internalType":"bool[]","name":"burned","type":"bool[]"},{"internalType":"uint256","name":"infernoPool","type":"uint256"},{"internalType":"uint256","name":"fluxPool","type":"uint256"},{"internalType":"uint256","name":"e280Pool","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdatedCycle","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minCyclePool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"nftLastBacking","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"nftLastClaim","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"infernoAmount","type":"uint256"},{"internalType":"uint256","name":"e280Amount","type":"uint256"}],"name":"register777CycleTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fluxHub","type":"address"}],"name":"setFluxHub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setMinCyclePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"totalTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"totalTokenPool","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":"updateCycle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"cycleId","type":"uint32"},{"internalType":"uint256","name":"totalMultipliers","type":"uint256"}],"name":"updateStoredMultipliers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"cycleId","type":"uint32"},{"internalType":"uint256","name":"totalMultipliers","type":"uint256"},{"internalType":"uint256","name":"multiplierDeduction","type":"uint256"}],"name":"updateStoredMultipliersOnBurn","outputs":[],"stateMutability":"nonpayable","type":"function"}]