文件 1 的 10:Context.sol
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 2 的 10:IERC165.sol
pragma solidity ^0.7.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 3 的 10:IERC20.sol
pragma solidity ^0.7.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function burn(uint256 burnQuantity) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 4 的 10:IERC721.sol
import "./ERC165/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}
文件 5 的 10:IERC721Enumerable.sol
import "./IERC721.sol";
interface IERC721Enumerable is IERC721 {
function totalSupply() external view returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
function tokenByIndex(uint256 index) external view returns (uint256);
}
文件 6 的 10:ISPT.sol
pragma solidity ^0.7.0;
import "./IERC20.sol";
interface ISPT is IERC20 {
function totalBurned() external view returns (uint256);
function totalFromSpirits() external view returns (uint256);
function totalFromAddons() external view returns (uint256);
function totalAccumulatedSupply() external view returns (uint256);
function accumulated(uint256 tokenIndex) external view returns (uint256);
function totalAccumulated(uint256 tokenIndex, bool useRewardMultiplier) external view returns (uint256);
function totalClaimed(uint256 tokenIndex) external view returns (uint256);
function accumulatedNode(uint256 nodeId) external view returns (uint256);
function totalAccumulatedNode(uint256 nodeId) external view returns (uint256);
function lastClaimNode(uint256 nodeId) external view returns (uint256);
function timeSinceLastClaimNode(uint256 nodeId) external view returns (uint256);
function nodeEmissionMultiplier(uint256 nodeType) external view returns (uint256);
function nodeEmissionRate(uint256 regTime) external view returns (uint256);
function totalClaimedNode(uint256 nodeId) external view returns (uint256);
function nodeEmissionEnds() external pure returns (uint256);
function canClaimFromNode(uint256 nodeId) external view returns (bool);
function totalAccumulatedDevFund() external view returns (uint256);
function totalClaimableDevFund() external view returns (uint256);
function totalClaimedDevFund() external view returns (uint256);
}
文件 7 的 10:ISpirits.sol
pragma solidity ^0.7.0;
import "./IERC721Enumerable.sol";
interface ISpirits is IERC721Enumerable {
function revealStageByIndex(uint256 index) external view returns (uint256);
function mintedTimestampByIndex(uint256 index) external view returns (uint256);
function nodeInfo(uint256 nodeId) external view returns (address, string memory, uint256, uint256, uint256, bool, uint256[] memory);
function nodeBalanceOf(address owner) external view returns (uint256);
function ownerOfNode(uint256 nodeId) external view returns (address);
function nodeOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
function totalNodes() external view returns (uint256);
function totalActiveNodes() external view returns (uint256);
function nodeType(uint256 nodeId) external view returns (uint256);
function nodeSize(uint256 nodeId) external view returns (uint256);
function nodeValid(uint256 nodeId) external view returns (bool);
function nodeRegTime(uint256 nodeId) external view returns (uint256);
function nodeUnregTime(uint256 nodeId) external view returns (uint256);
function nodeName(uint256 nodeId) external view returns (string memory);
function nodeActive(uint256 nodeId) external view returns (bool);
function nodeTokenIds(uint256 nodeId) external view returns (uint256[] memory);
function isNodeNameReserved(string memory nameString) external view returns (bool);
function nodeIdFromTokenId(uint256 tokenId) external view returns (uint256);
function nodeExists(uint256 nodeId) external view returns (bool);
function isUserNameReserved(string memory nameString) external view returns (bool);
function username(address owner) external view returns (string memory);
function tokenRewardMultiplier(uint256 tokenId) external view returns (uint256, uint256);
function testTokenRewardMultiplier(uint256 newNum, uint256 newDen) external pure returns (uint256);
}
文件 8 的 10:Ownable.sol
pragma solidity ^0.7.0;
import "./Context.sol";
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 9 的 10:SPT.sol
pragma solidity ^0.7.0;
import "./ERC165/IERC165.sol";
import "./utils/SafeMath.sol";
import "./IERC20.sol";
import "./ISPT.sol";
import "./ISpirits.sol";
import "./utils/Context.sol";
import "./utils/Ownable.sol";
contract SPT is Context, Ownable, ISPT {
using SafeMath for uint256;
uint256 public constant SECONDS_IN_A_DAY = 86400;
uint256 public constant SECONDS_IN_2_WEEKS = SECONDS_IN_A_DAY * 14;
uint256 public constant SECONDS_IN_A_YEAR = SECONDS_IN_A_DAY * 365;
uint256 public constant INITIAL_ALLOTMENT = 100 * (10 ** 18);
uint256 public constant EMISSION_START = 1625245200;
uint256 public constant EMISSION_END = EMISSION_START + (SECONDS_IN_A_YEAR * 3);
uint256 public constant EMISSION_END_NODE = EMISSION_START + (SECONDS_IN_A_YEAR * 6);
uint256 public constant EMISSION_PER_DAY_YEAR_0 = 1.00 * (10 ** 18);
uint256 public constant EMISSION_PER_DAY_YEAR_1 = 0.50 * (10 ** 18);
uint256 public constant EMISSION_PER_DAY_YEAR_2 = 0.25 * (10 ** 18);
uint256[3] public EMISSION_PER_DAY_YEARS = [EMISSION_PER_DAY_YEAR_0,
EMISSION_PER_DAY_YEAR_1,
EMISSION_PER_DAY_YEAR_2];
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
mapping(uint256 => uint256) private _lastClaim;
mapping(uint256 => uint256) private _claimedAmount;
mapping(uint256 => uint256) private _lastClaimNode;
mapping(uint256 => uint256) private _claimedAmountNode;
uint256 public nodeEmissionMultiplierType1 = 1;
uint256 public nodeEmissionMultiplierType2 = 5;
uint256 public nodeEmissionMultiplierType3 = 3;
uint256 public nodeEmissionMultiplierType4 = 12;
uint256 private _totalSupply;
uint256 private _totalBurned;
uint256 private _totalFromSpirits = 0;
uint256 private _totalFromAddons = 0;
uint256 private _claimedAmountDevFund = 0;
string private _name;
string private _symbol;
uint8 private _decimals;
address private _spiritsAddress;
address private _addonsAddress;
constructor () {
_name = "SpiritToken";
_symbol = "SPT";
_decimals = 18;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view returns (uint8) {
return _decimals;
}
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
function totalBurned() public view override returns (uint256) {
return _totalBurned;
}
function totalFromSpirits() public view override returns (uint256) {
return _totalFromSpirits;
}
function totalFromAddons() public view override returns (uint256) {
return _totalFromAddons;
}
function lastClaim(uint256 tokenIndex) public view returns (uint256) {
require(ISpirits(_spiritsAddress).ownerOf(tokenIndex) != address(0), "Owner cannot be 0 address");
require(tokenIndex < ISpirits(_spiritsAddress).totalSupply(), "NFT at index has not been minted yet");
uint256 lastClaimed = uint256(_lastClaim[tokenIndex]) != 0 ? uint256(_lastClaim[tokenIndex]) : EMISSION_START;
return lastClaimed;
}
function totalAccumulatedSupply() public view override returns (uint256) {
require(block.timestamp > EMISSION_START, "Emission has not started yet");
require(ISpirits(_spiritsAddress).ownerOf(0) != address(0), "Owner of NFT #0 cannot be 0 address");
uint256 nftSupply = ISpirits(_spiritsAddress).totalSupply();
require(nftSupply > 0, "No NFTs have been minted yet");
return nftSupply.mul(totalAccumulated(0, false));
}
function accumulated(uint256 tokenIndex) public view override returns (uint256) {
require(block.timestamp > EMISSION_START, "Emission has not started yet");
require(ISpirits(_spiritsAddress).ownerOf(tokenIndex) != address(0), "Owner cannot be 0 address");
require(tokenIndex < ISpirits(_spiritsAddress).totalSupply(), "NFT at index has not been minted yet");
uint256 lastClaimed = lastClaim(tokenIndex);
if (lastClaimed >= EMISSION_END) return 0;
uint256 accumulatedQty = totalAccumulated(tokenIndex, true).sub(totalClaimed(tokenIndex));
return accumulatedQty;
}
function totalAccumulated(uint256 tokenIndex, bool useRewardMultiplier) public view override returns (uint256) {
require(block.timestamp > EMISSION_START, "Emission has not started yet");
require(ISpirits(_spiritsAddress).ownerOf(tokenIndex) != address(0), "Owner cannot be 0 address");
require(tokenIndex < ISpirits(_spiritsAddress).totalSupply(), "NFT at index has not been minted yet");
uint256 nowTime = block.timestamp < EMISSION_END ? block.timestamp : EMISSION_END;
uint256 elapsedTime = nowTime.sub(EMISSION_START);
uint256 yearsElapsed = elapsedTime.div(SECONDS_IN_A_YEAR);
uint256 totalAmountAccumulated = 0;
uint256 timeAccountedFor = 0;
for(uint year = 0; year < yearsElapsed; year++) {
uint256 emissionPerDayForYear = EMISSION_PER_DAY_YEARS[year];
uint256 yearAccumulated = emissionPerDayForYear.mul(365);
totalAmountAccumulated = totalAmountAccumulated.add(yearAccumulated);
timeAccountedFor = timeAccountedFor.add(SECONDS_IN_A_YEAR);
}
if(elapsedTime > timeAccountedFor && yearsElapsed < 3) {
uint256 remainingTime = elapsedTime.sub(timeAccountedFor);
uint256 currentEmissionRate = EMISSION_PER_DAY_YEARS[yearsElapsed];
uint256 remainingAccumulated = remainingTime.mul(currentEmissionRate).div(SECONDS_IN_A_DAY);
totalAmountAccumulated = totalAmountAccumulated.add(remainingAccumulated);
}
if(useRewardMultiplier) {
uint256 rewardNum;
uint256 rewardDen;
(rewardNum, rewardDen) = ISpirits(_spiritsAddress).tokenRewardMultiplier(tokenIndex);
totalAmountAccumulated = (totalAmountAccumulated.mul(rewardNum)).div(rewardDen);
}
totalAmountAccumulated = totalAmountAccumulated.add(INITIAL_ALLOTMENT);
return totalAmountAccumulated;
}
function totalClaimed(uint256 tokenIndex) public view override returns (uint256) {
require(ISpirits(_spiritsAddress).ownerOf(tokenIndex) != address(0), "Owner cannot be 0 address");
require(tokenIndex < ISpirits(_spiritsAddress).totalSupply(), "NFT at index has not been minted yet");
uint256 claimed = uint256(_claimedAmount[tokenIndex]) >= 0 ? uint256(_claimedAmount[tokenIndex]) : 0;
return claimed;
}
function setSpiritsAddress(address spiritsAddress) onlyOwner public {
require(_spiritsAddress == address(0), "Already set");
_spiritsAddress = spiritsAddress;
}
function setAddonsAddress(address addonsAddress) onlyOwner public {
_addonsAddress = addonsAddress;
}
function claim(uint256[] memory tokenIndices) public returns (uint256) {
require(block.timestamp > EMISSION_START, "Emission has not started yet");
uint256 totalClaimQty = 0;
for (uint i = 0; i < tokenIndices.length; i++) {
require(tokenIndices[i] < ISpirits(_spiritsAddress).totalSupply(), "NFT at index has not been minted yet");
for (uint j = i + 1; j < tokenIndices.length; j++) {
require(tokenIndices[i] != tokenIndices[j], "Duplicate token index");
}
uint tokenIndex = tokenIndices[i];
require(ISpirits(_spiritsAddress).ownerOf(tokenIndex) == msg.sender, "Sender is not the owner");
uint256 claimQty = accumulated(tokenIndex);
if (claimQty != 0) {
_lastClaim[tokenIndex] = block.timestamp;
uint256 alreadyClaimed = _claimedAmount[tokenIndex];
_claimedAmount[tokenIndex] = alreadyClaimed.add(claimQty);
totalClaimQty = totalClaimQty.add(claimQty);
}
}
require(totalClaimQty != 0, "No accumulated SPT");
_mint(msg.sender, totalClaimQty);
return totalClaimQty;
}
function claimDev() onlyOwner public returns (uint256) {
require(block.timestamp > EMISSION_START, "Emission has not started yet");
uint256 claimQty = totalClaimableDevFund();
require(claimQty != 0, "No accumulated SPT");
_claimedAmountDevFund = _claimedAmountDevFund.add(claimQty);
_mint(msg.sender, claimQty);
return claimQty;
}
function totalAccumulatedDevFund() public view override returns (uint256) {
return totalAccumulatedSupply().div(20);
}
function totalClaimableDevFund() public view override returns (uint256) {
return totalAccumulatedDevFund().sub(totalClaimedDevFund());
}
function totalClaimedDevFund() public view override returns (uint256) {
return _claimedAmountDevFund;
}
function canClaimFromNode(uint256 nodeId) public view override returns (bool) {
if(ISpirits(_spiritsAddress).nodeActive(nodeId) && ISpirits(_spiritsAddress).nodeValid(nodeId) && timeSinceLastClaimNode(nodeId) >= SECONDS_IN_2_WEEKS) {
return true;
}
return false;
}
function claimNode(uint256 nodeId) public returns (uint256) {
require(block.timestamp > EMISSION_START, "Emission has not started yet");
require(ISpirits(_spiritsAddress).nodeActive(nodeId), "Node does not exist or has been unregistered");
require(ISpirits(_spiritsAddress).nodeValid(nodeId), "Node is not valid (pending approval by admin)");
require(ISpirits(_spiritsAddress).ownerOfNode(nodeId) == msg.sender, "Sender is not the node owner");
require(timeSinceLastClaimNode(nodeId) >= SECONDS_IN_2_WEEKS, "Must wait 14 days between claims");
uint256 claimQty = accumulatedNode(nodeId);
require(claimQty != 0, "No accumulated SPT");
_lastClaimNode[nodeId] = block.timestamp;
uint256 alreadyClaimed = _claimedAmountNode[nodeId];
_claimedAmountNode[nodeId] = alreadyClaimed.add(claimQty);
_mint(msg.sender, claimQty);
return claimQty;
}
function accumulatedNode(uint256 nodeId) public view override returns (uint256) {
require(ISpirits(_spiritsAddress).nodeExists(nodeId), "Node with specified id does not exist");
uint256 regTime = ISpirits(_spiritsAddress).nodeRegTime(nodeId);
require(regTime > 0 && block.timestamp > regTime, "Emission has not started yet");
uint256 lastClaimed = lastClaimNode(nodeId);
if (lastClaimed >= EMISSION_END_NODE) return 0;
uint256 accumulatedQty = totalAccumulatedNode(nodeId).sub(totalClaimedNode(nodeId));
return accumulatedQty;
}
function totalAccumulatedNode(uint256 nodeId) public view override returns (uint256) {
require(ISpirits(_spiritsAddress).nodeExists(nodeId), "Node with specified id does not exist");
uint256 regTime = ISpirits(_spiritsAddress).nodeRegTime(nodeId);
uint256 unregTime = ISpirits(_spiritsAddress).nodeUnregTime(nodeId);
uint256 nodeType = ISpirits(_spiritsAddress).nodeType(nodeId);
require(regTime > 0 && block.timestamp > regTime, "Emission has not started yet");
uint256 nowTime = block.timestamp;
if(unregTime > 0) {
nowTime = unregTime;
}
if(nowTime > EMISSION_END_NODE) {
nowTime = EMISSION_END_NODE;
}
if(nowTime <= regTime) {
return 0;
}
uint256 elapsedTime = nowTime.sub(regTime);
uint256 emissionRatePerDay = nodeEmissionRate(regTime).mul(nodeEmissionMultiplier(nodeType));
uint256 totalAmountAccumulated = elapsedTime.mul(emissionRatePerDay).div(SECONDS_IN_A_DAY);
return totalAmountAccumulated;
}
function lastClaimNode(uint256 nodeId) public view override returns (uint256) {
require(ISpirits(_spiritsAddress).nodeExists(nodeId), "Node with specified id does not exist");
uint256 regTime = ISpirits(_spiritsAddress).nodeRegTime(nodeId);
uint256 lastClaimed = uint256(_lastClaimNode[nodeId]) != 0 ? uint256(_lastClaimNode[nodeId]) : regTime;
return lastClaimed;
}
function timeSinceLastClaimNode(uint256 nodeId) public view override returns (uint256) {
require(ISpirits(_spiritsAddress).nodeExists(nodeId), "Node with specified id does not exist");
return block.timestamp - lastClaimNode(nodeId);
}
function nodeEmissionEnds() public pure override returns (uint256) {
return EMISSION_END_NODE;
}
function nodeEmissionMultiplier(uint256 nodeType) public view override returns (uint256) {
require(nodeType >= 1 && nodeType <= 4, "Invalid node type");
if(nodeType == 1) {
return nodeEmissionMultiplierType1;
}
if(nodeType == 2) {
return nodeEmissionMultiplierType2;
}
if(nodeType == 3) {
return nodeEmissionMultiplierType3;
}
if(nodeType == 4) {
return nodeEmissionMultiplierType4;
}
return nodeEmissionMultiplierType1;
}
function changeNodeEmissionMultiplier(uint256 nodeType, uint256 newMultiplier) onlyOwner public {
require(nodeType >= 1 && nodeType <= 4, "Invalid node type");
if(nodeType == 1) {
nodeEmissionMultiplierType1 = newMultiplier;
}
if(nodeType == 2) {
nodeEmissionMultiplierType2 = newMultiplier;
}
if(nodeType == 3) {
nodeEmissionMultiplierType3 = newMultiplier;
}
if(nodeType == 4) {
nodeEmissionMultiplierType4 = newMultiplier;
}
}
function nodeEmissionRate(uint256 regTime) public view override returns (uint256) {
uint256 band1 = EMISSION_START + (SECONDS_IN_A_YEAR * 1);
if(regTime <= band1) {
return EMISSION_PER_DAY_YEARS[0];
}
uint256 band2 = EMISSION_START + (SECONDS_IN_A_YEAR * 2);
if(regTime <= band2) {
return EMISSION_PER_DAY_YEARS[1];
}
return EMISSION_PER_DAY_YEARS[2];
}
function totalClaimedNode(uint256 nodeId) public view override returns (uint256) {
require(ISpirits(_spiritsAddress).nodeExists(nodeId), "Node with specified id does not exist");
uint256 claimed = uint256(_claimedAmountNode[nodeId]) >= 0 ? uint256(_claimedAmountNode[nodeId]) : 0;
return claimed;
}
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
if (msg.sender == _spiritsAddress) {
_totalFromSpirits = _totalFromSpirits.add(amount);
}
else if(_addonsAddress != address(0) && msg.sender == _addonsAddress) {
_totalFromAddons = _totalFromAddons.add(amount);
}
else {
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
}
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function burn(uint256 burnQuantity) public virtual override returns (bool) {
_burn(msg.sender, burnQuantity);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
_totalBurned = _totalBurned.add(amount);
emit Transfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _setupDecimals(uint8 decimals_) internal {
_decimals = decimals_;
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
文件 10 的 10:SafeMath.sol
pragma solidity ^0.7.0;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
{
"compilationTarget": {
"contracts/SPT.sol": "SPT"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"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":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","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":[],"name":"EMISSION_END","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMISSION_END_NODE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"EMISSION_PER_DAY_YEARS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMISSION_PER_DAY_YEAR_0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMISSION_PER_DAY_YEAR_1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMISSION_PER_DAY_YEAR_2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMISSION_START","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_ALLOTMENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SECONDS_IN_2_WEEKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SECONDS_IN_A_DAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SECONDS_IN_A_YEAR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenIndex","type":"uint256"}],"name":"accumulated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeId","type":"uint256"}],"name":"accumulatedNode","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"amount","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":"uint256","name":"burnQuantity","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeId","type":"uint256"}],"name":"canClaimFromNode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeType","type":"uint256"},{"internalType":"uint256","name":"newMultiplier","type":"uint256"}],"name":"changeNodeEmissionMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIndices","type":"uint256[]"}],"name":"claim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimDev","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeId","type":"uint256"}],"name":"claimNode","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenIndex","type":"uint256"}],"name":"lastClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeId","type":"uint256"}],"name":"lastClaimNode","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nodeEmissionEnds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeType","type":"uint256"}],"name":"nodeEmissionMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nodeEmissionMultiplierType1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nodeEmissionMultiplierType2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nodeEmissionMultiplierType3","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nodeEmissionMultiplierType4","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"regTime","type":"uint256"}],"name":"nodeEmissionRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addonsAddress","type":"address"}],"name":"setAddonsAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spiritsAddress","type":"address"}],"name":"setSpiritsAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeId","type":"uint256"}],"name":"timeSinceLastClaimNode","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenIndex","type":"uint256"},{"internalType":"bool","name":"useRewardMultiplier","type":"bool"}],"name":"totalAccumulated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAccumulatedDevFund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeId","type":"uint256"}],"name":"totalAccumulatedNode","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAccumulatedSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBurned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalClaimableDevFund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenIndex","type":"uint256"}],"name":"totalClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalClaimedDevFund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nodeId","type":"uint256"}],"name":"totalClaimedNode","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFromAddons","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFromSpirits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","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"}]