编译器
0.8.24+commit.e11b9ed9
文件 1 的 13: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;
}
}
文件 2 的 13:ERC721Holder.sol
pragma solidity ^0.8.20;
import {IERC721Receiver} from "../IERC721Receiver.sol";
abstract contract ERC721Holder is IERC721Receiver {
function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) {
return this.onERC721Received.selector;
}
}
文件 3 的 13:EnumerableSet.sol
pragma solidity ^0.8.20;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 value => uint256) _positions;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 position = set._positions[value];
if (position != 0) {
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
set._values[valueIndex] = lastValue;
set._positions[lastValue] = position;
}
set._values.pop();
delete set._positions[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly {
result := store
}
return result;
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 4 的 13:IERC165.sol
pragma solidity ^0.8.20;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 5 的 13: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);
}
文件 6 的 13:IERC721.sol
pragma solidity ^0.8.20;
import {IERC721} from "../token/ERC721/IERC721.sol";
文件 7 的 13:IERC721Receiver.sol
pragma solidity ^0.8.20;
interface IERC721Receiver {
function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data)
external
returns (bytes4);
}
文件 8 的 13:ILGNDX.sol
pragma solidity ^0.8.20;
interface ILGNDX {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function burn(uint256 value) external;
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 9 的 13:ITitanLegendsMarketplace.sol
pragma solidity ^0.8.24;
interface ITitanLegendsMarketplace {
function listings(uint256 listingId) external returns (uint256, uint256, address);
function buyListing(uint256 listingId, uint256 price) external;
function isListingActive(uint256 listingId) external returns (bool);
}
文件 10 的 13: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);
}
}
文件 11 的 13: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);
}
}
文件 12 的 13: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;
}
}
文件 13 的 13:TitanLegendsBattlefield.sol
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "@openzeppelin/contracts/interfaces/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "./ILGNDX.sol";
import "./ITitanLegendsMarketplace.sol";
contract TitanLegendsBattlefield is ERC721Holder, ReentrancyGuard, Ownable2Step {
using EnumerableSet for EnumerableSet.UintSet;
IERC721 public immutable titanLegends;
IERC20 public immutable titanX;
ITitanLegendsMarketplace public immutable marketplace;
ILGNDX public legendX;
uint256 public constant tokensPerBountyPoint = 59_954.112 ether;
uint256 public activationTime;
uint64 public maxPerBounty = 25;
bool public tokenSet;
bool public active;
bool public isClaimBurnDisabled;
bool public marketplaceExclusionEnabled;
EnumerableSet.UintSet private battle;
mapping(uint256 tokenId => bool) public isExcluded;
event BountyClaimed(address addr, uint256[] tokenIds);
event RansomPaid(address addr, uint256[] tokenIds);
constructor(address _titanLegends, address _titanX, address _marketplace) Ownable(msg.sender) {
titanLegends = IERC721(_titanLegends);
titanX = IERC20(_titanX);
marketplace = ITitanLegendsMarketplace(_marketplace);
}
function dragonsAtBattle() external view returns (uint256[] memory) {
return battle.values();
}
function getEarlyClaimBurn() public view returns (uint256) {
if (isClaimBurnDisabled) return 0;
uint256 daysPassed = (block.timestamp - activationTime) / 86400;
if (daysPassed > 24) return 0;
return 50 - daysPassed * 2;
}
function getMultiplier(uint256 tokenId) public pure returns (uint256) {
if (
tokenId == 46 || tokenId == 135 || tokenId == 212 || tokenId == 225 || tokenId == 427 || tokenId == 532
|| tokenId == 591 || tokenId == 694 || tokenId == 735 || tokenId == 811 || tokenId == 946 || tokenId == 1139
|| tokenId == 1210 || tokenId == 1237 || tokenId == 1357 || tokenId == 1457 || tokenId == 1503
|| tokenId == 1561 || tokenId == 1663 || tokenId == 1876 || tokenId == 1996 || tokenId == 2089
|| tokenId == 2251
) return 80;
if (tokenId > 1500) return 28;
return 10;
}
function processBountyNfts(uint256[] memory tokenIds) private returns (uint256 totalBounty, uint256 burnPool) {
uint256 earlyClaimBurn = getEarlyClaimBurn();
if (earlyClaimBurn > 0) {
uint256 multiplierPool;
for (uint256 i; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
uint256 burnPercent = isExcluded[tokenId] ? 3 : earlyClaimBurn + 3;
unchecked {
uint256 multiplier = getMultiplier(tokenId);
multiplierPool += multiplier;
burnPool += (multiplier * burnPercent * tokensPerBountyPoint) / 100;
}
titanLegends.safeTransferFrom(msg.sender, address(this), tokenId);
battle.add(tokenId);
}
totalBounty = multiplierPool * tokensPerBountyPoint;
} else {
uint256 multiplierPool;
for (uint256 i; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
unchecked {
multiplierPool += getMultiplier(tokenId);
}
titanLegends.safeTransferFrom(msg.sender, address(this), tokenId);
battle.add(tokenId);
}
totalBounty = multiplierPool * tokensPerBountyPoint;
burnPool = (totalBounty * 3) / 100;
}
return (totalBounty, burnPool);
}
function claimBounty(uint256[] calldata tokenIds) external nonReentrant {
require(active, "The Battlefield is not active");
require(tokenIds.length <= maxPerBounty, "Max number of dragons per bounty exceeded");
(uint256 totalBounty, uint256 burnPool) = processBountyNfts(tokenIds);
legendX.burn(burnPool);
legendX.transfer(msg.sender, totalBounty - burnPool);
emit BountyClaimed(msg.sender, tokenIds);
}
function payRansom(uint256[] calldata tokenIds) external nonReentrant {
require(active, "The Battlefield is not active");
uint256 multiplierPool;
bool isGracePeriod = getEarlyClaimBurn() > 0;
for (uint256 i; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
unchecked {
multiplierPool += getMultiplier(tokenId);
}
titanLegends.safeTransferFrom(address(this), msg.sender, tokenId);
if (isGracePeriod) isExcluded[tokenId] = true;
battle.remove(tokenId);
}
uint256 ransomPool = multiplierPool * tokensPerBountyPoint;
uint256 burnPool = (ransomPool * 3) / 100;
legendX.transferFrom(msg.sender, address(this), ransomPool + burnPool);
legendX.burn(burnPool);
emit RansomPaid(msg.sender, tokenIds);
}
function purchaseListingFromMarketplace(uint256 listingId, uint256 price) external nonReentrant {
require(getEarlyClaimBurn() > 0, "Only available during grace period");
require(marketplaceExclusionEnabled, "Function disabled");
titanX.transferFrom(msg.sender, address(this), price);
titanX.approve(address(marketplace), price);
(uint256 tokenId,,) = marketplace.listings(listingId);
marketplace.buyListing(listingId, price);
isExcluded[tokenId] = true;
titanLegends.safeTransferFrom(address(this), msg.sender, tokenId);
}
function setMaxPerBounty(uint64 _limit) external onlyOwner {
maxPerBounty = _limit;
}
function addExemption(uint256[] calldata tokenIds) external onlyOwner {
for (uint256 i; i < tokenIds.length; i++) {
isExcluded[tokenIds[i]] = true;
}
}
function setToken(address tokenAddress) external onlyOwner {
require(!tokenSet, "Can only be done once");
legendX = ILGNDX(tokenAddress);
tokenSet = true;
}
function setMarketplaceExclusion(bool isEnabled) external onlyOwner {
marketplaceExclusionEnabled = isEnabled;
}
function disableEarlyClaimBurn() external onlyOwner {
isClaimBurnDisabled = true;
}
function activateBattlefield() external onlyOwner {
require(tokenSet, "Token is not set");
require(!active, "Battlefield is already active");
active = true;
marketplaceExclusionEnabled = true;
activationTime = block.timestamp;
}
}
{
"compilationTarget": {
"contracts/TitanLegendsBattlefield.sol": "TitanLegendsBattlefield"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_titanLegends","type":"address"},{"internalType":"address","name":"_titanX","type":"address"},{"internalType":"address","name":"_marketplace","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"BountyClaimed","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"RansomPaid","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activateBattlefield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activationTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"active","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"addExemption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"claimBounty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableEarlyClaimBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dragonsAtBattle","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEarlyClaimBurn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"isClaimBurnDisabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isExcluded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"legendX","outputs":[{"internalType":"contract ILGNDX","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketplace","outputs":[{"internalType":"contract ITitanLegendsMarketplace","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketplaceExclusionEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPerBounty","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"payRansom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"listingId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"purchaseListingFromMarketplace","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isEnabled","type":"bool"}],"name":"setMarketplaceExclusion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_limit","type":"uint64"}],"name":"setMaxPerBounty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"setToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"titanLegends","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"titanX","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenSet","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokensPerBountyPoint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]