编译器
0.8.26+commit.8a97fa7a
文件 1 的 19:BurnInfo.sol
pragma solidity ^0.8.21;
import "../libs/constant.sol";
abstract contract BurnInfo {
uint256 private s_totalShogunBurned;
mapping(address => uint256) private s_userBurnAmount;
mapping(address => uint256) private s_project_BurnAmount;
mapping(address => mapping(address => uint256)) private s_projectUser_BurnAmount;
event ShogunBurned(address indexed user, address indexed project, uint256 amount);
function _updateBurnAmount(address user, address project, uint256 amount) internal {
s_userBurnAmount[user] += amount;
s_totalShogunBurned += amount;
if (project != address(0)) {
s_project_BurnAmount[project] += amount;
s_projectUser_BurnAmount[project][user] += amount;
}
emit ShogunBurned(user, project, amount);
}
function getTotalBurnTotal() public view returns (uint256) {
return s_totalShogunBurned;
}
function getUserBurnTotal(address user) public view returns (uint256) {
return s_userBurnAmount[user];
}
function getProjectBurnTotal(address contractAddress) public view returns (uint256) {
return s_project_BurnAmount[contractAddress];
}
function getProjectUserBurnTotal(
address contractAddress,
address user
) public view returns (uint256) {
return s_projectUser_BurnAmount[contractAddress][user];
}
}
文件 2 的 19: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 的 19:ERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual returns (string memory) {
return _name;
}
function symbol() public view virtual returns (string memory) {
return _symbol;
}
function decimals() public view virtual returns (uint8) {
return 18;
}
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
_totalSupply -= value;
}
} else {
unchecked {
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
文件 4 的 19:GlobalInfo.sol
pragma solidity ^0.8.21;
import "../libs/constant.sol";
import "../interfaces/IShogunBnB.sol";
error Shogun_InvalidRange();
abstract contract GlobalInfo {
uint256 private immutable i_genesisTs;
uint256 private s_currentContractDay;
uint256 private s_currentAuctionSupply;
uint256 private s_currentWarChestSupply;
mapping(address => mapping(uint256 => uint256)) s_userCycleAmount;
mapping(uint256 => uint256) private s_cycleTotal;
mapping(uint256 => uint256) private s_cycleSupplyPerShare;
mapping(address => uint256) private s_userStartAuctionClaimIndex;
struct CycleAuctionInfo {
uint256 day;
uint256 amount;
uint256 reward;
}
event GlobalDailyUpdateStats(uint256 indexed day, uint256 indexed auctionSupply);
event CalculatedAuctionSupplyPerShare(uint256 indexed day, uint256 indexed supplyPerShare);
modifier dailyUpdate(address bnbAddress) {
_dailyUpdate(bnbAddress);
_;
}
constructor() {
i_genesisTs = block.timestamp;
s_currentContractDay = 1;
s_currentAuctionSupply = INITIAL_PHASE_DAILY_AUCTION_SUPPLY;
}
function _dailyUpdate(address bnbAddress) private {
uint256 currentContractDay = s_currentContractDay;
uint256 currentBlockDay = ((block.timestamp - i_genesisTs) / 1 days) + 1;
if (currentBlockDay > currentContractDay) {
if (currentContractDay < 28) {
_calculateCycleSupplyPerShare(
currentContractDay,
INITIAL_PHASE_DAILY_AUCTION_SUPPLY
);
emit GlobalDailyUpdateStats(currentBlockDay, INITIAL_PHASE_DAILY_AUCTION_SUPPLY);
} else {
_calculateCycleSupplyPerShare(currentContractDay, s_currentAuctionSupply);
uint256 newAuctionSupply = (s_currentWarChestSupply *
PHASE_2_DAILY_AUCTION_SUPPLY_PERCENT) / PERCENT_BPS;
s_currentAuctionSupply = newAuctionSupply;
s_currentWarChestSupply -= newAuctionSupply;
emit GlobalDailyUpdateStats(currentBlockDay, newAuctionSupply);
}
s_currentContractDay = currentBlockDay;
IShogunBnB(bnbAddress).dailyUpdate();
}
}
function _calculateCycleSupplyPerShare(uint256 contractDay, uint256 auctionSupply) internal {
uint256 supplyPerShare;
uint256 totalAmount = s_cycleTotal[contractDay];
if (totalAmount != 0) {
supplyPerShare = (auctionSupply * 1 ether) / totalAmount;
s_cycleSupplyPerShare[contractDay] = supplyPerShare;
}
emit CalculatedAuctionSupplyPerShare(contractDay, supplyPerShare);
}
function _updateCycleAmount(address user, uint256 amount) internal {
uint256 currentContractDay = getCurrentContractDay();
if (s_userStartAuctionClaimIndex[user] == 0) {
s_userStartAuctionClaimIndex[user] = currentContractDay;
}
s_userCycleAmount[user][currentContractDay] += amount;
s_cycleTotal[currentContractDay] += amount;
}
function _updateUserAuctionClaimIndex(address user) internal {
s_userStartAuctionClaimIndex[user] = getCurrentContractDay();
}
function _AddWarChestSupply(uint256 amount) internal {
s_currentWarChestSupply += amount;
}
function getCurrentContractDay() public view returns (uint256) {
return s_currentContractDay;
}
function getCurrentAuctionSupply() public view returns (uint256) {
return s_currentAuctionSupply;
}
function getCurrentWarChestSupply() public view returns (uint256) {
return s_currentWarChestSupply;
}
function genesisTs() public view returns (uint256) {
return i_genesisTs;
}
function getSupplyPerShare(uint256 index) public view returns (uint256) {
return s_cycleSupplyPerShare[index];
}
function getCycleTotalAmount(uint256 day) public view returns (uint256) {
return s_cycleTotal[day];
}
function getUserCycleAmount(address user, uint256 day) public view returns (uint256) {
return s_userCycleAmount[user][day];
}
function getUserStartAuctionClaimIndex(address user) public view returns (uint256) {
return s_userStartAuctionClaimIndex[user];
}
function getUserClaimableAuctionSupply(
address user
) public view returns (uint256 claimableSupply) {
uint256 startClaimIndex = s_userStartAuctionClaimIndex[user];
uint256 maxContractDay = getCurrentContractDay();
for (uint256 i = startClaimIndex; i < maxContractDay; i++) {
claimableSupply += s_userCycleAmount[user][i] * s_cycleSupplyPerShare[i];
}
if (claimableSupply != 0) claimableSupply /= 1 ether;
}
function getUserAuctionInfo(
address user,
uint256 startDay,
uint256 endDay
) public view returns (CycleAuctionInfo[] memory cycleAuctionInfo) {
if (startDay > endDay) revert Shogun_InvalidRange();
uint256 currentContractDay = getCurrentContractDay();
endDay = endDay > currentContractDay ? currentContractDay : endDay;
uint256 index = 0;
cycleAuctionInfo = new CycleAuctionInfo[](endDay - startDay + 1);
for (uint256 i = startDay; i <= endDay; i++) {
uint256 amount = s_userCycleAmount[user][i];
cycleAuctionInfo[index++] = CycleAuctionInfo({
day: i,
amount: amount,
reward: (amount * s_cycleSupplyPerShare[i]) / 1 ether
});
}
}
}
文件 5 的 19:IERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
文件 6 的 19: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);
}
文件 7 的 19:IERC20Metadata.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 8 的 19:IShogun.sol
pragma solidity ^0.8.21;
interface IShogun {
function mintLPTokens() external;
function burnCAShogun(address contractAddress) external;
function genesisTs() external returns (uint256);
function getGenesisAddress() external returns (address);
function getLPAddress() external returns (address);
}
文件 9 的 19:IShogunBnB.sol
pragma solidity ^0.8.21;
interface IShogunBnB {
function dailyUpdate() external;
}
文件 10 的 19:IShogunOnBurn.sol
pragma solidity ^0.8.21;
interface IShogunOnBurn {
function onBurn(address user, uint256 amount) external;
}
文件 11 的 19:ITITANX.sol
pragma solidity ^0.8.21;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface ITITANX is IERC20 {
enum StakeStatus {
ACTIVE,
ENDED,
BURNED
}
struct UserStakeInfo {
uint152 titanAmount;
uint128 shares;
uint16 numOfDays;
uint48 stakeStartTs;
uint48 maturityTs;
StakeStatus status;
}
function startMint(uint256 mintPower, uint256 numOfDays) external payable;
function batchMint(uint256 mintPower, uint256 numOfDays, uint256 count) external payable;
function claimMint(uint256 id) external;
function batchClaimMint() external;
function startStake(uint256 amount, uint256 numOfDays) external;
function getUserStakeInfo(address user, uint256 id) external returns (UserStakeInfo memory);
function approveBurnStakes(address spender, uint256 amount) external returns (bool);
function allowanceBurnStakes(address user, address spender) external view returns (uint256);
function burnLPTokens() external;
}
文件 12 的 19:ITitanBurn.sol
pragma solidity ^0.8.21;
interface ITitanBurn {
function burnTokens(
address user,
uint256 amount,
uint256 userRebatePercentage,
uint256 rewardPaybackPercentage
) external;
function burnTokensToPayAddress(
address user,
uint256 amount,
uint256 userRebatePercentage,
uint256 rewardPaybackPercentage,
address rewardPaybackAddress
) external;
function burnMint(address userAddress, uint256 id) external;
function burnStake(
address userAddress,
uint256 id,
uint256 userRebatePercentage,
uint256 rewardPaybackPercentage
) external;
function burnStakeToPayAddress(
address userAddress,
uint256 id,
uint256 userRebatePercentage,
uint256 rewardPaybackPercentage,
address rewardPaybackAddress
) external;
}
文件 13 的 19:ITitanOnBurn.sol
pragma solidity ^0.8.21;
interface ITitanOnBurn {
function onBurn(address user, uint256 amount) external;
}
文件 14 的 19:IX28.sol
pragma solidity ^0.8.21;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IX28 is IERC20 {
function mintX28withTitanX(uint256 amount) external;
function burnCAX28(address contractAddress) external;
}
文件 15 的 19: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);
}
}
文件 16 的 19:ReentrancyGuard.sol
pragma solidity ^0.8.20;
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
_status = ENTERED;
}
function _nonReentrantAfter() private {
_status = NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
文件 17 的 19:Shogun.sol
pragma solidity ^0.8.21;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/interfaces/IERC165.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../interfaces/ITITANX.sol";
import "../interfaces/ITitanBurn.sol";
import "../interfaces/ITitanOnBurn.sol";
import "../interfaces/IShogunOnBurn.sol";
import "../interfaces/IShogun.sol";
import "../interfaces/IX28.sol";
import "./GlobalInfo.sol";
import "./BurnInfo.sol";
error Shogun_NotSupportedContract();
error Shogun_NotAllowed();
error Shogun_InvalidBurnRewardPercent();
error Shogun_LPTokensHasMinted();
error Shogun_InvalidAddress();
error Shogun_UnregisteredCA();
error Shogun_NoSupplyToClaim();
error Shogun_NoAllowance();
error Shogun_NotEnoughBalance();
error Shogun_BurnStakeClosed();
error Shogun_CannotZero();
contract Shogun is ERC20, ReentrancyGuard, GlobalInfo, BurnInfo, Ownable, ITitanOnBurn {
address private s_genesisAddress;
address private s_lPAddress;
address private s_buyAndBurnAddress;
uint256 s_totalX28Deposited;
uint256 s_totalX28Burned;
uint256 s_totalTitanXDeposited;
uint256 s_totalTitanXBurned;
uint256 s_totalShogunTaxBurned;
mapping(address => bool) s_buyAndBurnAddressRegistry;
mapping(address => bool) private s_taxExclusionList;
bool private s_initialLPMinted;
event AuctionEntered(address indexed user, uint256 indexed day, uint256 indexed amount);
event AuctionSupplyClaimed(address indexed user, uint256 indexed amount);
constructor(
address genesisAddress,
address lPAddress,
address buyAndBurnAddress
) Ownable(msg.sender) ERC20("SHOGUN", "SHOGUN") {
if (genesisAddress == address(0)) revert Shogun_InvalidAddress();
if (lPAddress == address(0)) revert Shogun_InvalidAddress();
if (buyAndBurnAddress == address(0)) revert Shogun_InvalidAddress();
s_genesisAddress = genesisAddress;
s_lPAddress = lPAddress;
s_buyAndBurnAddress = buyAndBurnAddress;
s_buyAndBurnAddressRegistry[buyAndBurnAddress] = true;
s_taxExclusionList[buyAndBurnAddress] = true;
s_taxExclusionList[lPAddress] = true;
s_taxExclusionList[address(0)] = true;
_mint(s_lPAddress, LP_WALLET_TOKENS);
}
function addTaxExclusionAddress(address addr) external onlyOwner {
if (addr == address(0)) revert Shogun_InvalidAddress();
s_taxExclusionList[addr] = true;
}
function removeTaxExclusionAddress(address addr) external onlyOwner {
if (addr == address(0)) revert Shogun_InvalidAddress();
s_taxExclusionList[addr] = false;
}
function setBuyAndBurnContractAddress(address contractAddress) external onlyOwner {
if (
!IERC165(contractAddress).supportsInterface(IERC165.supportsInterface.selector) ||
!IERC165(contractAddress).supportsInterface(type(IShogun).interfaceId)
) revert Shogun_NotSupportedContract();
s_buyAndBurnAddress = contractAddress;
s_buyAndBurnAddressRegistry[contractAddress] = true;
s_taxExclusionList[contractAddress] = true;
}
function setNewGenesisAddress(address newAddress) external {
if (msg.sender != s_genesisAddress) revert Shogun_NotAllowed();
if (newAddress == address(0)) revert Shogun_InvalidAddress();
s_genesisAddress = newAddress;
}
function setNewLPAddress(address newAddress) external {
if (msg.sender != s_lPAddress) revert Shogun_NotAllowed();
if (newAddress == address(0)) revert Shogun_InvalidAddress();
s_lPAddress = newAddress;
s_taxExclusionList[newAddress] = true;
}
function mintLPTokens() external {
if (msg.sender != s_buyAndBurnAddress) revert Shogun_NotAllowed();
if (s_initialLPMinted) revert Shogun_LPTokensHasMinted();
s_initialLPMinted = true;
_mint(s_buyAndBurnAddress, INITAL_LP_TOKENS);
}
function burnCAShogun(address contractAddress) external dailyUpdate(s_buyAndBurnAddress) {
if (!s_buyAndBurnAddressRegistry[contractAddress]) revert Shogun_UnregisteredCA();
uint256 totalAmount = balanceOf(contractAddress);
uint256 lPAmount = (totalAmount * SHOGUN_LP_PERCENT) / PERCENT_BPS;
uint256 warChestAmount = (totalAmount * SHOGUN_WARCHEST_PERCENT) / PERCENT_BPS;
super._update(contractAddress, address(0), totalAmount - lPAmount);
super._update(contractAddress, s_lPAddress, lPAmount);
_AddWarChestSupply(warChestAmount);
}
function enterAuctionX28Liquid(
uint256 amount
) external dailyUpdate(s_buyAndBurnAddress) nonReentrant {
if (amount == 0) revert Shogun_CannotZero();
uint256 burnAmount = (amount * BURN_PERCENT) / PERCENT_BPS;
IX28(X28).transferFrom(msg.sender, X28_BNB, burnAmount);
IX28(X28).burnCAX28(X28_BNB);
uint256 lPAmount = (amount * LP_PERCENT) / PERCENT_BPS;
IX28(X28).transferFrom(msg.sender, s_lPAddress, lPAmount);
uint256 genesisAmount = (amount * GENESIS_PERCENT) / PERCENT_BPS;
IX28(X28).transferFrom(msg.sender, s_genesisAddress, genesisAmount);
IX28(X28).transferFrom(
msg.sender,
s_buyAndBurnAddress,
amount - burnAmount - lPAmount - genesisAmount
);
_updateCycleAmount(msg.sender, amount);
s_totalX28Deposited += amount;
s_totalX28Burned += burnAmount;
emit AuctionEntered(msg.sender, getCurrentContractDay(), amount);
}
function enterAuctionTitanXStake(
uint256[] calldata stakeId
) external dailyUpdate(s_buyAndBurnAddress) nonReentrant {
if (getCurrentContractDay() > 28) revert Shogun_BurnStakeClosed();
if (ITITANX(TITANX_CA).allowanceBurnStakes(msg.sender, address(this)) < stakeId.length)
revert Shogun_NoAllowance();
uint256 amount;
uint256 claimCount;
for (uint256 i = 0; i < stakeId.length; i++) {
ITITANX.UserStakeInfo memory info = ITITANX(TITANX_CA).getUserStakeInfo(
msg.sender,
stakeId[i]
);
if (info.status == ITITANX.StakeStatus.ACTIVE && info.titanAmount != 0) {
ITitanBurn(TITANX_CA).burnStakeToPayAddress(
msg.sender,
stakeId[i],
0,
8,
s_buyAndBurnAddress
);
amount += info.titanAmount;
++claimCount;
}
if (claimCount == MAX_BATCH_BURN_COUNT) break;
}
if (ITITANX(TITANX_CA).balanceOf(msg.sender) < amount) revert Shogun_NotEnoughBalance();
uint256 burnAmount = (amount * BURN_PERCENT) / PERCENT_BPS;
ITITANX(TITANX_CA).transferFrom(msg.sender, TITANX_BNBV2, burnAmount);
ITITANX(TITANX_CA).burnLPTokens();
uint256 lPAmount = (amount * LP_PERCENT) / PERCENT_BPS;
ITITANX(TITANX_CA).transferFrom(msg.sender, s_lPAddress, lPAmount);
uint256 genesisAmount = (amount * GENESIS_PERCENT) / PERCENT_BPS;
ITITANX(TITANX_CA).transferFrom(msg.sender, s_genesisAddress, genesisAmount);
ITITANX(TITANX_CA).transferFrom(
msg.sender,
s_buyAndBurnAddress,
amount - burnAmount - lPAmount - genesisAmount
);
uint256 totalCreditAmount = amount * 2;
_updateCycleAmount(msg.sender, totalCreditAmount);
s_totalTitanXDeposited += totalCreditAmount;
s_totalTitanXBurned += burnAmount + amount;
emit AuctionEntered(msg.sender, getCurrentContractDay(), totalCreditAmount);
}
function claimUserAuction() external dailyUpdate(s_buyAndBurnAddress) nonReentrant {
uint256 claimableSupply = getUserClaimableAuctionSupply(msg.sender);
if (claimableSupply == 0) revert Shogun_NoSupplyToClaim();
_updateUserAuctionClaimIndex(msg.sender);
_mint(msg.sender, claimableSupply);
emit AuctionSupplyClaimed(msg.sender, claimableSupply);
}
function onBurn(address user, uint256 amount) external {}
function _update(address from, address to, uint256 value) internal virtual override {
if (s_taxExclusionList[from] || s_taxExclusionList[to]) {
super._update(from, to, value);
return;
}
uint256 taxAmount = (value * TRANSFER_TAX_PERCENT) / PERCENT_BPS;
uint256 lPAmount = (taxAmount * SHOGUN_LP_PERCENT) / PERCENT_BPS;
uint256 warChestAmount = (taxAmount * SHOGUN_WARCHEST_PERCENT) / PERCENT_BPS;
super._update(from, address(0), taxAmount - lPAmount);
super._update(from, s_lPAddress, lPAmount);
super._update(from, to, value - taxAmount);
_AddWarChestSupply(warChestAmount);
s_totalShogunTaxBurned += taxAmount - lPAmount - warChestAmount;
}
function _burnLiquidShogun(
address user,
uint256 amount,
uint256 userRebatePercentage,
uint256 rewardPaybackPercentage,
address rewardPaybackAddress
) private {
_spendAllowance(user, msg.sender, amount);
_burnbefore(userRebatePercentage, rewardPaybackPercentage);
_burn(user, amount);
_burnAfter(
user,
amount,
userRebatePercentage,
rewardPaybackPercentage,
rewardPaybackAddress
);
}
function _burnbefore(
uint256 userRebatePercentage,
uint256 rewardPaybackPercentage
) private view {
if (rewardPaybackPercentage + userRebatePercentage > MAX_BURN_REWARD_PERCENT)
revert Shogun_InvalidBurnRewardPercent();
if (
!IERC165(msg.sender).supportsInterface(IERC165.supportsInterface.selector) ||
!IERC165(msg.sender).supportsInterface(type(IShogunOnBurn).interfaceId)
) revert Shogun_NotSupportedContract();
}
function _burnAfter(
address user,
uint256 amount,
uint256 userRebatePercentage,
uint256 rewardPaybackPercentage,
address rewardPaybackAddress
) private {
_updateBurnAmount(user, msg.sender, amount);
uint256 devFee;
uint256 userRebate;
if (rewardPaybackPercentage != 0) devFee = (amount * rewardPaybackPercentage) / 100;
if (userRebatePercentage != 0) userRebate = (amount * userRebatePercentage) / 100;
if (devFee != 0) _mint(rewardPaybackAddress, devFee);
if (userRebate != 0) _mint(user, userRebate);
IShogunOnBurn(msg.sender).onBurn(user, amount);
}
function supportsInterface(bytes4 interfaceId) public pure returns (bool) {
return
interfaceId == IERC165.supportsInterface.selector ||
interfaceId == type(ITitanOnBurn).interfaceId;
}
function getGenesisAddress() public view returns (address) {
return s_genesisAddress;
}
function getLPAddress() public view returns (address) {
return s_lPAddress;
}
function getBuyAndBurnAddress() public view returns (address) {
return s_buyAndBurnAddress;
}
function getBuyAndBurnAddressRegistry(address contractAddress) public view returns (bool) {
return s_buyAndBurnAddressRegistry[contractAddress];
}
function isAddressTaxExcluded(address user) public view returns (bool) {
return s_taxExclusionList[user];
}
function getTotalX28Deposited() public view returns (uint256) {
return s_totalX28Deposited;
}
function getTotalX28BurnedFromDeposits() public view returns (uint256) {
return s_totalX28Burned;
}
function getTotalTitanXDeposited() public view returns (uint256) {
return s_totalTitanXDeposited;
}
function getTotalTitanXBurnedFromDeposits() public view returns (uint256) {
return s_totalTitanXBurned;
}
function getTotalShogunBurnedFromTax() public view returns (uint256) {
return s_totalShogunTaxBurned;
}
function manualDailyUpdate() public dailyUpdate(s_buyAndBurnAddress) {}
function burnTokensToPayAddress(
address user,
uint256 amount,
uint256 userRebatePercentage,
uint256 rewardPaybackPercentage,
address rewardPaybackAddress
) public nonReentrant dailyUpdate(s_buyAndBurnAddress) {
_burnLiquidShogun(
user,
amount,
userRebatePercentage,
rewardPaybackPercentage,
rewardPaybackAddress
);
}
function burnTokens(
address user,
uint256 amount,
uint256 userRebatePercentage,
uint256 rewardPaybackPercentage
) public nonReentrant dailyUpdate(s_buyAndBurnAddress) {
_burnLiquidShogun(user, amount, userRebatePercentage, rewardPaybackPercentage, msg.sender);
}
function userBurnTokens(uint256 amount) public nonReentrant dailyUpdate(s_buyAndBurnAddress) {
_burn(msg.sender, amount);
_updateBurnAmount(msg.sender, address(0), amount);
}
}
文件 18 的 19:constant.sol
pragma solidity ^0.8.21;
address constant TITANX_CA = 0xF19308F923582A6f7c465e5CE7a9Dc1BEC6665B1;
address constant TITANX_BNBV2 = 0x410e10C33a49279f78CB99c8d816F18D5e7D5404;
address constant X28 = 0x5c47902c8C80779CB99235E42C354E53F38C3B0d;
address constant X28_BNB = 0xa3144E7FCceD79Ce6ff6E14AE9d8DF229417A7a2;
uint256 constant GENESIS_PERCENT = 5_00;
uint256 constant BURN_PERCENT = 20_00;
uint256 constant LP_PERCENT = 22_00;
uint256 constant BNB_PERCENT = 53_00;
uint256 constant TRANSFER_TAX_PERCENT = 8_00;
uint256 constant SHOGUN_BURN_PERCENT = 28_00;
uint256 constant SHOGUN_LP_PERCENT = 8_00;
uint256 constant SHOGUN_WARCHEST_PERCENT = 64_00;
uint256 constant PERCENT_BPS = 100_00;
uint256 constant INITAL_LP_TOKENS = 1_000_000 ether;
uint256 constant LP_WALLET_TOKENS = 100_000_000 ether;
uint256 constant INITIAL_PHASE_DAILY_AUCTION_SUPPLY = 100_000_000 ether;
uint256 constant PHASE_2_DAILY_AUCTION_SUPPLY_PERCENT = 8_00;
uint256 constant MAX_BATCH_BURN_COUNT = 28;
uint256 constant MAX_BURN_REWARD_PERCENT = 8;
文件 19 的 19:draft-IERC6093.sol
pragma solidity ^0.8.20;
interface IERC20Errors {
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
error ERC20InvalidSender(address sender);
error ERC20InvalidReceiver(address receiver);
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
error ERC20InvalidApprover(address approver);
error ERC20InvalidSpender(address spender);
}
interface IERC721Errors {
error ERC721InvalidOwner(address owner);
error ERC721NonexistentToken(uint256 tokenId);
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
error ERC721InvalidSender(address sender);
error ERC721InvalidReceiver(address receiver);
error ERC721InsufficientApproval(address operator, uint256 tokenId);
error ERC721InvalidApprover(address approver);
error ERC721InvalidOperator(address operator);
}
interface IERC1155Errors {
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
error ERC1155InvalidSender(address sender);
error ERC1155InvalidReceiver(address receiver);
error ERC1155MissingApprovalForAll(address operator, address owner);
error ERC1155InvalidApprover(address approver);
error ERC1155InvalidOperator(address operator);
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
{
"compilationTarget": {
"ttx_shogun/contracts/Shogun.sol": "Shogun"
},
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"genesisAddress","type":"address"},{"internalType":"address","name":"lPAddress","type":"address"},{"internalType":"address","name":"buyAndBurnAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","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":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"Shogun_BurnStakeClosed","type":"error"},{"inputs":[],"name":"Shogun_CannotZero","type":"error"},{"inputs":[],"name":"Shogun_InvalidAddress","type":"error"},{"inputs":[],"name":"Shogun_InvalidBurnRewardPercent","type":"error"},{"inputs":[],"name":"Shogun_InvalidRange","type":"error"},{"inputs":[],"name":"Shogun_LPTokensHasMinted","type":"error"},{"inputs":[],"name":"Shogun_NoAllowance","type":"error"},{"inputs":[],"name":"Shogun_NoSupplyToClaim","type":"error"},{"inputs":[],"name":"Shogun_NotAllowed","type":"error"},{"inputs":[],"name":"Shogun_NotEnoughBalance","type":"error"},{"inputs":[],"name":"Shogun_NotSupportedContract","type":"error"},{"inputs":[],"name":"Shogun_UnregisteredCA","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"day","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AuctionEntered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AuctionSupplyClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"day","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"supplyPerShare","type":"uint256"}],"name":"CalculatedAuctionSupplyPerShare","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"day","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"auctionSupply","type":"uint256"}],"name":"GlobalDailyUpdateStats","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":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"project","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ShogunBurned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"addTaxExclusionAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"burnCAShogun","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"userRebatePercentage","type":"uint256"},{"internalType":"uint256","name":"rewardPaybackPercentage","type":"uint256"}],"name":"burnTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"userRebatePercentage","type":"uint256"},{"internalType":"uint256","name":"rewardPaybackPercentage","type":"uint256"},{"internalType":"address","name":"rewardPaybackAddress","type":"address"}],"name":"burnTokensToPayAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimUserAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"stakeId","type":"uint256[]"}],"name":"enterAuctionTitanXStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"enterAuctionX28Liquid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"genesisTs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBuyAndBurnAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"getBuyAndBurnAddressRegistry","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentAuctionSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentContractDay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentWarChestSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"day","type":"uint256"}],"name":"getCycleTotalAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGenesisAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLPAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"getProjectBurnTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"getProjectUserBurnTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getSupplyPerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalBurnTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalShogunBurnedFromTax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalTitanXBurnedFromDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalTitanXDeposited","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalX28BurnedFromDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalX28Deposited","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"startDay","type":"uint256"},{"internalType":"uint256","name":"endDay","type":"uint256"}],"name":"getUserAuctionInfo","outputs":[{"components":[{"internalType":"uint256","name":"day","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"}],"internalType":"struct GlobalInfo.CycleAuctionInfo[]","name":"cycleAuctionInfo","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserBurnTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserClaimableAuctionSupply","outputs":[{"internalType":"uint256","name":"claimableSupply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"day","type":"uint256"}],"name":"getUserCycleAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserStartAuctionClaimIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"isAddressTaxExcluded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manualDailyUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintLPTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"onBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"removeTaxExclusionAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"}],"name":"setBuyAndBurnContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"setNewGenesisAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAddress","type":"address"}],"name":"setNewLPAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"userBurnTokens","outputs":[],"stateMutability":"nonpayable","type":"function"}]