Skip to content

Instantly share code, notes, and snippets.

@hackfisher
Created December 12, 2020 10:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hackfisher/1e2414b6748e5f5bed2222d713896f1c to your computer and use it in GitHub Desktop.
Save hackfisher/1e2414b6748e5f5bed2222d713896f1c to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.4.13+commit.fb4cb1a.js&optimize=true&runs=200&gist=
pragma solidity >=0.4.22 <0.7.0;
/**
* @title Storage
* @dev Store & retrieve value in a variable
*/
contract Storage {
uint256 number;
/**
* @dev Store value in variable
* @param num value to store
*/
function store(uint256 num) public {
number = num;
}
/**
* @dev Return value
* @return value of 'number'
*/
function retrieve() public view returns (uint256){
return number;
}
}
pragma solidity >=0.4.22 <0.7.0;
/**
* @title Owner
* @dev Set & change owner
*/
contract Owner {
address private owner;
// event for EVM logging
event OwnerSet(address indexed oldOwner, address indexed newOwner);
// modifier to check if caller is owner
modifier isOwner() {
// If the first argument of 'require' evaluates to 'false', execution terminates and all
// changes to the state and to Ether balances are reverted.
// This used to consume all gas in old EVM versions, but not anymore.
// It is often a good idea to use 'require' to check if functions are called correctly.
// As a second argument, you can also provide an explanation about what went wrong.
require(msg.sender == owner, "Caller is not owner");
_;
}
/**
* @dev Set contract deployer as owner
*/
constructor() public {
owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor
emit OwnerSet(address(0), owner);
}
/**
* @dev Change owner
* @param newOwner address of new owner
*/
function changeOwner(address newOwner) public isOwner {
emit OwnerSet(owner, newOwner);
owner = newOwner;
}
/**
* @dev Return owner address
* @return address of owner
*/
function getOwner() external view returns (address) {
return owner;
}
}
pragma solidity >=0.4.22 <0.7.0;
/**
* @title Ballot
* @dev Implements voting process along with vote delegation
*/
contract Ballot {
struct Voter {
uint weight; // weight is accumulated by delegation
bool voted; // if true, that person already voted
address delegate; // person delegated to
uint vote; // index of the voted proposal
}
struct Proposal {
// If you can limit the length to a certain number of bytes,
// always use one of bytes1 to bytes32 because they are much cheaper
bytes32 name; // short name (up to 32 bytes)
uint voteCount; // number of accumulated votes
}
address public chairperson;
mapping(address => Voter) public voters;
Proposal[] public proposals;
/**
* @dev Create a new ballot to choose one of 'proposalNames'.
* @param proposalNames names of proposals
*/
constructor(bytes32[] memory proposalNames) public {
chairperson = msg.sender;
voters[chairperson].weight = 1;
for (uint i = 0; i < proposalNames.length; i++) {
// 'Proposal({...})' creates a temporary
// Proposal object and 'proposals.push(...)'
// appends it to the end of 'proposals'.
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}
/**
* @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'.
* @param voter address of voter
*/
function giveRightToVote(address voter) public {
require(
msg.sender == chairperson,
"Only chairperson can give right to vote."
);
require(
!voters[voter].voted,
"The voter already voted."
);
require(voters[voter].weight == 0);
voters[voter].weight = 1;
}
/**
* @dev Delegate your vote to the voter 'to'.
* @param to address to which vote is delegated
*/
function delegate(address to) public {
Voter storage sender = voters[msg.sender];
require(!sender.voted, "You already voted.");
require(to != msg.sender, "Self-delegation is disallowed.");
while (voters[to].delegate != address(0)) {
to = voters[to].delegate;
// We found a loop in the delegation, not allowed.
require(to != msg.sender, "Found loop in delegation.");
}
sender.voted = true;
sender.delegate = to;
Voter storage delegate_ = voters[to];
if (delegate_.voted) {
// If the delegate already voted,
// directly add to the number of votes
proposals[delegate_.vote].voteCount += sender.weight;
} else {
// If the delegate did not vote yet,
// add to her weight.
delegate_.weight += sender.weight;
}
}
/**
* @dev Give your vote (including votes delegated to you) to proposal 'proposals[proposal].name'.
* @param proposal index of proposal in the proposals array
*/
function vote(uint proposal) public {
Voter storage sender = voters[msg.sender];
require(sender.weight != 0, "Has no right to vote");
require(!sender.voted, "Already voted.");
sender.voted = true;
sender.vote = proposal;
// If 'proposal' is out of the range of the array,
// this will throw automatically and revert all
// changes.
proposals[proposal].voteCount += sender.weight;
}
/**
* @dev Computes the winning proposal taking all previous votes into account.
* @return winningProposal_ index of winning proposal in the proposals array
*/
function winningProposal() public view
returns (uint winningProposal_)
{
uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) {
if (proposals[p].voteCount > winningVoteCount) {
winningVoteCount = proposals[p].voteCount;
winningProposal_ = p;
}
}
}
/**
* @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then
* @return winnerName_ the name of the winner
*/
function winnerName() public view
returns (bytes32 winnerName_)
{
winnerName_ = proposals[winningProposal()].name;
}
}
// File: openzeppelin-solidity/contracts/introspection/ERC165.sol
pragma solidity ^0.4.24;
/**
* @title ERC165
* @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
*/
interface ERC165 {
/**
* @notice Query if a contract implements an interface
* @param _interfaceId The interface identifier, as specified in ERC-165
* @dev Interface identification is specified in ERC-165. This function
* uses less than 30,000 gas.
*/
function supportsInterface(bytes4 _interfaceId)
external
view
returns (bool);
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721Basic.sol
pragma solidity ^0.4.24;
/**
* @title ERC721 Non-Fungible Token Standard basic interface
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Basic is ERC165 {
bytes4 internal constant InterfaceId_ERC721 = 0x80ac58cd;
/*
* 0x80ac58cd ===
* bytes4(keccak256('balanceOf(address)')) ^
* bytes4(keccak256('ownerOf(uint256)')) ^
* bytes4(keccak256('approve(address,uint256)')) ^
* bytes4(keccak256('getApproved(uint256)')) ^
* bytes4(keccak256('setApprovalForAll(address,bool)')) ^
* bytes4(keccak256('isApprovedForAll(address,address)')) ^
* bytes4(keccak256('transferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
*/
bytes4 internal constant InterfaceId_ERC721Exists = 0x4f558e79;
/*
* 0x4f558e79 ===
* bytes4(keccak256('exists(uint256)'))
*/
bytes4 internal constant InterfaceId_ERC721Enumerable = 0x780e9d63;
/**
* 0x780e9d63 ===
* bytes4(keccak256('totalSupply()')) ^
* bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^
* bytes4(keccak256('tokenByIndex(uint256)'))
*/
bytes4 internal constant InterfaceId_ERC721Metadata = 0x5b5e139f;
/**
* 0x5b5e139f ===
* bytes4(keccak256('name()')) ^
* bytes4(keccak256('symbol()')) ^
* bytes4(keccak256('tokenURI(uint256)'))
*/
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) public view returns (uint256 _balance);
function ownerOf(uint256 _tokenId) public view returns (address _owner);
function exists(uint256 _tokenId) public view returns (bool _exists);
function approve(address _to, uint256 _tokenId) public;
function getApproved(uint256 _tokenId)
public view returns (address _operator);
function setApprovalForAll(address _operator, bool _approved) public;
function isApprovedForAll(address _owner, address _operator)
public view returns (bool);
function transferFrom(address _from, address _to, uint256 _tokenId) public;
function safeTransferFrom(address _from, address _to, uint256 _tokenId)
public;
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes _data
)
public;
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721.sol
pragma solidity ^0.4.24;
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Enumerable is ERC721Basic {
function totalSupply() public view returns (uint256);
function tokenOfOwnerByIndex(
address _owner,
uint256 _index
)
public
view
returns (uint256 _tokenId);
function tokenByIndex(uint256 _index) public view returns (uint256);
}
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Metadata is ERC721Basic {
function name() external view returns (string _name);
function symbol() external view returns (string _symbol);
function tokenURI(uint256 _tokenId) public view returns (string);
}
/**
* @title ERC-721 Non-Fungible Token Standard, full implementation interface
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata {
}
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
pragma solidity ^0.4.24;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* See https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address _who) public view returns (uint256);
function transfer(address _to, uint256 _value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
pragma solidity ^0.4.24;
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address _owner, address _spender)
public view returns (uint256);
function transferFrom(address _from, address _to, uint256 _value)
public returns (bool);
function approve(address _spender, uint256 _value) public returns (bool);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
// File: @evolutionland/common/contracts/interfaces/ISettingsRegistry.sol
pragma solidity ^0.4.24;
contract ISettingsRegistry {
enum SettingsValueTypes { NONE, UINT, STRING, ADDRESS, BYTES, BOOL, INT }
function uintOf(bytes32 _propertyName) public view returns (uint256);
function stringOf(bytes32 _propertyName) public view returns (string);
function addressOf(bytes32 _propertyName) public view returns (address);
function bytesOf(bytes32 _propertyName) public view returns (bytes);
function boolOf(bytes32 _propertyName) public view returns (bool);
function intOf(bytes32 _propertyName) public view returns (int);
function setUintProperty(bytes32 _propertyName, uint _value) public;
function setStringProperty(bytes32 _propertyName, string _value) public;
function setAddressProperty(bytes32 _propertyName, address _value) public;
function setBytesProperty(bytes32 _propertyName, bytes _value) public;
function setBoolProperty(bytes32 _propertyName, bool _value) public;
function setIntProperty(bytes32 _propertyName, int _value) public;
function getValueTypeOf(bytes32 _propertyName) public view returns (uint /* SettingsValueTypes */ );
event ChangeProperty(bytes32 indexed _propertyName, uint256 _type);
}
// File: @evolutionland/common/contracts/interfaces/IObjectOwnership.sol
pragma solidity ^0.4.24;
contract IObjectOwnership {
function mintObject(address _to, uint128 _objectId) public returns (uint256 _tokenId);
function burnObject(address _to, uint128 _objectId) public returns (uint256 _tokenId);
}
// File: @evolutionland/common/contracts/interfaces/ITokenUse.sol
pragma solidity ^0.4.24;
contract ITokenUse {
uint48 public constant MAX_UINT48_TIME = 281474976710655;
function isObjectInHireStage(uint256 _tokenId) public view returns (bool);
function isObjectReadyToUse(uint256 _tokenId) public view returns (bool);
function getTokenUser(uint256 _tokenId) public view returns (address);
function createTokenUseOffer(uint256 _tokenId, uint256 _duration, uint256 _price, address _acceptedActivity) public;
function cancelTokenUseOffer(uint256 _tokenId) public;
function takeTokenUseOffer(uint256 _tokenId) public;
function addActivity(uint256 _tokenId, address _user, uint256 _endTime) public;
function removeActivity(uint256 _tokenId, address _user) public;
}
// File: @evolutionland/common/contracts/interfaces/IMinerObject.sol
pragma solidity ^0.4.24;
contract IMinerObject is ERC165 {
bytes4 internal constant InterfaceId_IMinerObject = 0x64272b75;
/*
* 0x64272b752 ===
* bytes4(keccak256('strengthOf(uint256,address)'))
*/
function strengthOf(uint256 _tokenId, address _resourceToken, uint256 _landTokenId) public view returns (uint256);
}
// File: @evolutionland/common/contracts/interfaces/IActivityObject.sol
pragma solidity ^0.4.24;
contract IActivityObject is ERC165 {
bytes4 internal constant InterfaceId_IActivityObject = 0x2b9eccc6;
/*
* 0x2b9eccc6 ===
* bytes4(keccak256('activityAdded(uint256,address,address)')) ^
* bytes4(keccak256('activityRemoved(uint256,address,address)'))
*/
function activityAdded(uint256 _tokenId, address _activity, address _user) public;
function activityRemoved(uint256 _tokenId, address _activity, address _user) public;
}
// File: @evolutionland/common/contracts/interfaces/IActivity.sol
pragma solidity ^0.4.24;
contract IActivity is ERC165 {
bytes4 internal constant InterfaceId_IActivity = 0x6086e7f8;
/*
* 0x6086e7f8 ===
* bytes4(keccak256('activityStopped(uint256)'))
*/
function activityStopped(uint256 _tokenId) public;
}
// File: @evolutionland/common/contracts/interfaces/IAuthority.sol
pragma solidity ^0.4.24;
contract IAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
// File: @evolutionland/common/contracts/DSAuth.sol
pragma solidity ^0.4.24;
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
/**
* @title DSAuth
* @dev The DSAuth contract is reference implement of https://github.com/dapphub/ds-auth
* But in the isAuthorized method, the src from address(this) is remove for safty concern.
*/
contract DSAuth is DSAuthEvents {
IAuthority public authority;
address public owner;
constructor() public {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
emit LogSetOwner(owner);
}
function setAuthority(IAuthority authority_)
public
auth
{
authority = authority_;
emit LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == owner) {
return true;
} else if (authority == IAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
// File: @evolutionland/common/contracts/PausableDSAuth.sol
pragma solidity ^0.4.24;
/**
* @title Pausable
* @dev Base contract which allows children to implement an emergency stop mechanism.
*/
contract PausableDSAuth is DSAuth {
event Pause();
event Unpause();
bool public paused = false;
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*/
modifier whenNotPaused() {
require(!paused);
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*/
modifier whenPaused() {
require(paused);
_;
}
/**
* @dev called by the owner to pause, triggers stopped state
*/
function pause() public onlyOwner whenNotPaused {
paused = true;
emit Pause();
}
/**
* @dev called by the owner to unpause, returns to normal state
*/
function unpause() public onlyOwner whenPaused {
paused = false;
emit Unpause();
}
}
// File: @evolutionland/common/contracts/interfaces/ERC223.sol
pragma solidity ^0.4.23;
contract ERC223 {
function transfer(address to, uint amount, bytes data) public returns (bool ok);
function transferFrom(address from, address to, uint256 amount, bytes data) public returns (bool ok);
event ERC223Transfer(address indexed from, address indexed to, uint amount, bytes data);
}
// File: openzeppelin-solidity/contracts/introspection/SupportsInterfaceWithLookup.sol
pragma solidity ^0.4.24;
/**
* @title SupportsInterfaceWithLookup
* @author Matt Condon (@shrugs)
* @dev Implements ERC165 using a lookup table.
*/
contract SupportsInterfaceWithLookup is ERC165 {
bytes4 public constant InterfaceId_ERC165 = 0x01ffc9a7;
/**
* 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)'))
*/
/**
* @dev a mapping of interface id to whether or not it's supported
*/
mapping(bytes4 => bool) internal supportedInterfaces;
/**
* @dev A contract implementing SupportsInterfaceWithLookup
* implement ERC165 itself
*/
constructor()
public
{
_registerInterface(InterfaceId_ERC165);
}
/**
* @dev implement supportsInterface(bytes4) using a lookup table
*/
function supportsInterface(bytes4 _interfaceId)
external
view
returns (bool)
{
return supportedInterfaces[_interfaceId];
}
/**
* @dev private method for registering an interface
*/
function _registerInterface(bytes4 _interfaceId)
internal
{
require(_interfaceId != 0xffffffff);
supportedInterfaces[_interfaceId] = true;
}
}
// File: @evolutionland/common/contracts/SettingIds.sol
pragma solidity ^0.4.24;
/**
Id definitions for SettingsRegistry.sol
Can be used in conjunction with the settings registry to get properties
*/
contract SettingIds {
bytes32 public constant CONTRACT_RING_ERC20_TOKEN = "CONTRACT_RING_ERC20_TOKEN";
bytes32 public constant CONTRACT_KTON_ERC20_TOKEN = "CONTRACT_KTON_ERC20_TOKEN";
bytes32 public constant CONTRACT_GOLD_ERC20_TOKEN = "CONTRACT_GOLD_ERC20_TOKEN";
bytes32 public constant CONTRACT_WOOD_ERC20_TOKEN = "CONTRACT_WOOD_ERC20_TOKEN";
bytes32 public constant CONTRACT_WATER_ERC20_TOKEN = "CONTRACT_WATER_ERC20_TOKEN";
bytes32 public constant CONTRACT_FIRE_ERC20_TOKEN = "CONTRACT_FIRE_ERC20_TOKEN";
bytes32 public constant CONTRACT_SOIL_ERC20_TOKEN = "CONTRACT_SOIL_ERC20_TOKEN";
bytes32 public constant CONTRACT_OBJECT_OWNERSHIP = "CONTRACT_OBJECT_OWNERSHIP";
bytes32 public constant CONTRACT_TOKEN_LOCATION = "CONTRACT_TOKEN_LOCATION";
bytes32 public constant CONTRACT_LAND_BASE = "CONTRACT_LAND_BASE";
bytes32 public constant CONTRACT_USER_POINTS = "CONTRACT_USER_POINTS";
bytes32 public constant CONTRACT_INTERSTELLAR_ENCODER = "CONTRACT_INTERSTELLAR_ENCODER";
bytes32 public constant CONTRACT_DIVIDENDS_POOL = "CONTRACT_DIVIDENDS_POOL";
bytes32 public constant CONTRACT_TOKEN_USE = "CONTRACT_TOKEN_USE";
bytes32 public constant CONTRACT_REVENUE_POOL = "CONTRACT_REVENUE_POOL";
bytes32 public constant CONTRACT_ERC721_BRIDGE = "CONTRACT_ERC721_BRIDGE";
bytes32 public constant CONTRACT_PET_BASE = "CONTRACT_PET_BASE";
// Cut owner takes on each auction, measured in basis points (1/100 of a percent).
// this can be considered as transaction fee.
// Values 0-10,000 map to 0%-100%
// set ownerCut to 4%
// ownerCut = 400;
bytes32 public constant UINT_AUCTION_CUT = "UINT_AUCTION_CUT"; // Denominator is 10000
bytes32 public constant UINT_TOKEN_OFFER_CUT = "UINT_TOKEN_OFFER_CUT"; // Denominator is 10000
// Cut referer takes on each auction, measured in basis points (1/100 of a percent).
// which cut from transaction fee.
// Values 0-10,000 map to 0%-100%
// set refererCut to 4%
// refererCut = 400;
bytes32 public constant UINT_REFERER_CUT = "UINT_REFERER_CUT";
bytes32 public constant CONTRACT_LAND_RESOURCE = "CONTRACT_LAND_RESOURCE";
}
// File: contracts/ApostleSettingIds.sol
pragma solidity ^0.4.24;
contract ApostleSettingIds is SettingIds {
bytes32 public constant CONTRACT_GENE_SCIENCE = "CONTRACT_GENE_SCIENCE";
/// @notice The minimum payment required to use breedWithAuto(). This fee goes towards
/// the gas cost paid by the auto-birth daemon, and can be dynamically updated by
/// the COO role as the gas price changes.
bytes32 public constant UINT_AUTOBIRTH_FEE = "UINT_AUTOBIRTH_FEE";
bytes32 public constant CONTRACT_APOSTLE_BASE = "CONTRACT_APOSTLE_BASE";
bytes32 public constant CONTRACT_SIRING_AUCTION = "CONTRACT_SIRING_AUCTION";
bytes32 public constant CONTRACT_APOSTLE_AUCTION = "CONTRACT_APOSTLE_AUCTION";
bytes32 public constant CONTRACT_HABERG_POTION_SHOP = "CONTRACT_HABERG_POTION_SHOP";
// when player wants to buy their apostle some talents
// the minimum or unit they need to pay
bytes32 public constant UINT_MIX_TALENT = "UINT_MIX_TALENT";
bytes32 public constant UINT_APOSTLE_BID_WAITING_TIME = "UINT_APOSTLE_BID_WAITING_TIME";
/// Denominator is 100000000
bytes32 public constant UINT_HABERG_POTION_TAX_RATE = "UINT_HABERG_POTION_TAX_RATE";
// TODO: move this to common-contract
bytes32 public constant CONTRACT_LAND_RESOURCE = "CONTRACT_LAND_RESOURCE";
}
// File: contracts/interfaces/IGeneScience.sol
pragma solidity ^0.4.24;
/// @title defined the interface that will be referenced in main Kitty contract
contract IGeneScience {
/// @dev simply a boolean to indicate this is the contract we expect to be
function isGeneScience() public pure returns (bool);
/// @dev given genes of apostle 1 & 2, return a genetic combination - may have a random factor
/// @param genes1 genes of mom
/// @param genes2 genes of sire
/// @param talents1 talents of mom
/// @param talents2 talents of sire
/// @return the genes and talents that are supposed to be passed down the child
function mixGenesAndTalents(uint256 genes1, uint256 genes2, uint256 talents1, uint256 talents2, address resouceToken, uint256 level) public returns (uint256, uint256);
function getStrength(uint256 _talents, address _resourceToken, uint256 _landTokenId) public view returns (uint256);
function isOkWithRaceAndGender(uint _matronGenes, uint _sireGenes) public view returns (bool);
function enhanceWithMirrorToken(uint256 _talents, uint256 _mirrorTokenId) public view returns (uint256);
function removeMirrorToken(uint256 _addedTalents, uint256 _mirrorTokenId) public view returns (uint256);
}
// File: contracts/interfaces/IHabergPotionShop.sol
pragma solidity ^0.4.24;
contract IHabergPotionShop {
function tryKillApostle(uint256 _tokenId, address _killer) public;
function harbergLifeTime(uint256 _tokenId) public view;
}
// File: contracts/interfaces/ILandBase.sol
pragma solidity ^0.4.24;
contract ILandBase {
function resourceToken2RateAttrId(address _resourceToken) public view returns (uint256);
}
// File: contracts/ApostleBaseV2.sol
pragma solidity ^0.4.24;
// all Ids in this contracts refer to index which is using 128-bit unsigned integers.
// this is CONTRACT_APOSTLE_BASE
contract ApostleBaseV2 is SupportsInterfaceWithLookup, IActivity, IActivityObject, IMinerObject, PausableDSAuth, ApostleSettingIds {
event Birth(
address indexed owner, uint256 apostleTokenId, uint256 matronId, uint256 sireId, uint256 genes, uint256 talents, uint256 coolDownIndex, uint256 generation, uint256 birthTime
);
event Pregnant(
uint256 matronId,uint256 matronCoolDownEndTime, uint256 matronCoolDownIndex, uint256 sireId, uint256 sireCoolDownEndTime, uint256 sireCoolDownIndex
);
/// @dev The AutoBirth event is fired when a cat becomes pregant via the breedWithAuto()
/// function. This is used to notify the auto-birth daemon that this breeding action
/// included a pre-payment of the gas required to call the giveBirth() function.
event AutoBirth(uint256 matronId, uint256 cooldownEndTime);
event Unbox(uint256 tokenId, uint256 activeTime);
struct Apostle {
// An apostles genes never change.
uint256 genes;
uint256 talents;
// the ID of the parents of this Apostle. set to 0 for gen0 apostle.
// Note that using 128-bit unsigned integers to represent parents IDs,
// which refer to lastApostleObjectId for those two.
uint256 matronId;
uint256 sireId;
// Set to the ID of the sire apostle for matrons that are pregnant,
// zero otherwise. A non-zero value here is how we know an apostle
// is pregnant. Used to retrieve the genetic material for the new
// apostle when the birth transpires.
uint256 siringWithId;
// Set to the index in the cooldown array (see below) that represents
// the current cooldown duration for this apostle.
uint16 cooldownIndex;
// The "generation number" of this apostle.
uint16 generation;
uint48 birthTime;
uint48 activeTime;
uint48 deadTime;
uint48 cooldownEndTime;
}
uint32[14] public cooldowns = [
uint32(1 minutes),
uint32(2 minutes),
uint32(5 minutes),
uint32(10 minutes),
uint32(30 minutes),
uint32(1 hours),
uint32(2 hours),
uint32(4 hours),
uint32(8 hours),
uint32(16 hours),
uint32(1 days),
uint32(2 days),
uint32(4 days),
uint32(7 days)
];
/*
* Modifiers
*/
modifier singletonLockCall() {
require(!singletonLock, "Only can call once");
_;
singletonLock = true;
}
modifier isHuman() {
require(msg.sender == tx.origin, "robot is not permitted");
_;
}
/*** STORAGE ***/
bool private singletonLock = false;
uint128 public lastApostleObjectId;
ISettingsRegistry public registry;
mapping(uint256 => Apostle) public tokenId2Apostle;
mapping(uint256 => address) public sireAllowedToAddress;
function initializeContract(address _registry) public singletonLockCall {
// Ownable constructor
owner = msg.sender;
emit LogSetOwner(msg.sender);
registry = ISettingsRegistry(_registry);
_registerInterface(InterfaceId_IActivity);
_registerInterface(InterfaceId_IActivityObject);
_registerInterface(InterfaceId_IMinerObject);
_updateCoolDown();
}
// called by gen0Apostle
function createApostle(
uint256 _matronId, uint256 _sireId, uint256 _generation, uint256 _genes, uint256 _talents, address _owner) public auth returns (uint256) {
_createApostle(_matronId, _sireId, _generation, _genes, _talents, _owner);
}
function _createApostle(
uint256 _matronId, uint256 _sireId, uint256 _generation, uint256 _genes, uint256 _talents, address _owner) internal returns (uint256) {
require(_generation <= 65535);
uint256 coolDownIndex = _generation / 2;
if (coolDownIndex > 13) {
coolDownIndex = 13;
}
Apostle memory apostle = Apostle({
genes : _genes,
talents : _talents,
birthTime : uint48(now),
activeTime : 0,
deadTime : 0,
cooldownEndTime : 0,
matronId : _matronId,
sireId : _sireId,
siringWithId : 0,
cooldownIndex : uint16(coolDownIndex),
generation : uint16(_generation)
});
lastApostleObjectId += 1;
require(lastApostleObjectId <= 340282366920938463463374607431768211455, "Can not be stored with 128 bits.");
uint256 tokenId = IObjectOwnership(registry.addressOf(CONTRACT_OBJECT_OWNERSHIP)).mintObject(_owner, uint128(lastApostleObjectId));
tokenId2Apostle[tokenId] = apostle;
emit Birth(_owner, tokenId, apostle.matronId, apostle.sireId, _genes, _talents, uint256(coolDownIndex), uint256(_generation), now);
return tokenId;
}
function getCooldownDuration(uint256 _tokenId) public view returns (uint256){
uint256 cooldownIndex = tokenId2Apostle[_tokenId].cooldownIndex;
return cooldowns[cooldownIndex];
}
// @dev Checks to see if a apostle is able to breed.
// @param _apostleId - index of apostles which is within uint128.
function isReadyToBreed(uint256 _apostleId)
public
view
returns (bool)
{
require(tokenId2Apostle[_apostleId].birthTime > 0, "Apostle should exist");
require(ITokenUse(registry.addressOf(CONTRACT_TOKEN_USE)).isObjectReadyToUse(_apostleId), "Object ready to do activity");
// In addition to checking the cooldownEndTime, we also need to check to see if
// the cat has a pending birth; there can be some period of time between the end
// of the pregnacy timer and the birth event.
return (tokenId2Apostle[_apostleId].siringWithId == 0) && (tokenId2Apostle[_apostleId].cooldownEndTime <= now);
}
function approveSiring(address _addr, uint256 _sireId)
public
whenNotPaused
{
ERC721 objectOwnership = ERC721(registry.addressOf(SettingIds.CONTRACT_OBJECT_OWNERSHIP));
require(objectOwnership.ownerOf(_sireId) == msg.sender);
sireAllowedToAddress[_sireId] = _addr;
}
// check apostle's owner or siring permission
function _isSiringPermitted(uint256 _sireId, uint256 _matronId) internal view returns (bool) {
ERC721 objectOwnership = ERC721(registry.addressOf(SettingIds.CONTRACT_OBJECT_OWNERSHIP));
address matronOwner = objectOwnership.ownerOf(_matronId);
address sireOwner = objectOwnership.ownerOf(_sireId);
// Siring is okay if they have same owner, or if the matron's owner was given
// permission to breed with this sire.
return (matronOwner == sireOwner || sireAllowedToAddress[_sireId] == matronOwner);
}
function _triggerCooldown(uint256 _tokenId) internal returns (uint256) {
Apostle storage aps = tokenId2Apostle[_tokenId];
// Compute the end of the cooldown time (based on current cooldownIndex)
aps.cooldownEndTime = uint48(now + uint256(cooldowns[aps.cooldownIndex]));
// Increment the breeding count, clamping it at 13, which is the length of the
// cooldowns array. We could check the array size dynamically, but hard-coding
// this as a constant saves gas. Yay, Solidity!
if (aps.cooldownIndex < 13) {
aps.cooldownIndex += 1;
}
// address(0) meaning use by its owner or whitelisted contract
ITokenUse(registry.addressOf(SettingIds.CONTRACT_TOKEN_USE)).addActivity(_tokenId, address(0), aps.cooldownEndTime);
return uint256(aps.cooldownEndTime);
}
function _isReadyToGiveBirth(Apostle storage _matron) private view returns (bool) {
return (_matron.siringWithId != 0) && (_matron.cooldownEndTime <= now);
}
/// @dev Internal check to see if a given sire and matron are a valid mating pair. DOES NOT
/// check ownership permissions (that is up to the caller).
/// @param _matron A reference to the apostle struct of the potential matron.
/// @param _matronId The matron's ID.
/// @param _sire A reference to the apostle struct of the potential sire.
/// @param _sireId The sire's ID
function _isValidMatingPair(
Apostle storage _matron,
uint256 _matronId,
Apostle storage _sire,
uint256 _sireId
)
private
view
returns (bool)
{
// An apostle can't breed with itself!
if (_matronId == _sireId) {
return false;
}
// Apostles can't breed with their parents.
if (_matron.matronId == _sireId || _matron.sireId == _sireId) {
return false;
}
if (_sire.matronId == _matronId || _sire.sireId == _matronId) {
return false;
}
// We can short circuit the sibling check (below) if either cat is
// gen zero (has a matron ID of zero).
if (_sire.matronId == 0 || _matron.matronId == 0) {
return true;
}
// Apostles can't breed with full or half siblings.
if (_sire.matronId == _matron.matronId || _sire.matronId == _matron.sireId) {
return false;
}
if (_sire.sireId == _matron.matronId || _sire.sireId == _matron.sireId) {
return false;
}
// Everything seems cool! Let's get DTF.
return true;
}
function canBreedWith(uint256 _matronId, uint256 _sireId)
public
view
returns (bool)
{
require(_matronId > 0);
require(_sireId > 0);
Apostle storage matron = tokenId2Apostle[_matronId];
Apostle storage sire = tokenId2Apostle[_sireId];
return _isValidMatingPair(matron, _matronId, sire, _sireId) &&
_isSiringPermitted(_sireId, _matronId) &&
IGeneScience(registry.addressOf(CONTRACT_GENE_SCIENCE)).isOkWithRaceAndGender(matron.genes, sire.genes);
}
// only can be called by SiringClockAuction
function breedWithInAuction(uint256 _matronId, uint256 _sireId) public auth returns (bool) {
_breedWith(_matronId, _sireId);
Apostle storage matron = tokenId2Apostle[_matronId];
emit AutoBirth(_matronId, matron.cooldownEndTime);
return true;
}
function _breedWith(uint256 _matronId, uint256 _sireId) internal {
require(canBreedWith(_matronId, _sireId));
require(isReadyToBreed(_matronId));
require(isReadyToBreed(_sireId));
// Grab a reference to the Apostles from storage.
Apostle storage sire = tokenId2Apostle[_sireId];
Apostle storage matron = tokenId2Apostle[_matronId];
// Mark the matron as pregnant, keeping track of who the sire is.
matron.siringWithId = _sireId;
// Trigger the cooldown for both parents.
uint sireCoolDownEndTime = _triggerCooldown(_sireId);
uint matronCoolDownEndTime = _triggerCooldown(_matronId);
// Clear siring permission for both parents. This may not be strictly necessary
// but it's likely to avoid confusion!
delete sireAllowedToAddress[_matronId];
delete sireAllowedToAddress[_sireId];
// Emit the pregnancy event.
emit Pregnant(
_matronId, matronCoolDownEndTime, uint256(matron.cooldownIndex), _sireId, sireCoolDownEndTime, uint256(sire.cooldownIndex));
}
function breedWithAuto(uint256 _matronId, uint256 _sireId)
public
whenNotPaused
{
// Check for payment
// caller must approve first.
uint256 autoBirthFee = registry.uintOf(ApostleSettingIds.UINT_AUTOBIRTH_FEE);
ERC20 ring = ERC20(registry.addressOf(CONTRACT_RING_ERC20_TOKEN));
require(ring.transferFrom(msg.sender, address(this), autoBirthFee));
// Call through the normal breeding flow
_breedWith(_matronId, _sireId);
// Emit an AutoBirth message so the autobirth daemon knows when and for what cat to call
// giveBirth().
Apostle storage matron = tokenId2Apostle[_matronId];
emit AutoBirth(_matronId, uint48(matron.cooldownEndTime));
}
/// @notice Have a pregnant apostle give birth!
/// @param _matronId An apostle ready to give birth.
/// @return The apostle tokenId of the new Apostles.
/// @dev Looks at a given apostle and, if pregnant and if the gestation period has passed,
/// combines the genes of the two parents to create a new Apostles. The new apostle is assigned
/// to the current owner of the matron. Upon successful completion, both the matron and the
/// new Apostles will be ready to breed again. Note that anyone can call this function (if they
/// are willing to pay the gas!), but the new Apostles always goes to the mother's owner.
function giveBirth(uint256 _matronId, address _resourceToken, uint256 _level)
public
isHuman
whenNotPaused
{
Apostle storage matron = tokenId2Apostle[_matronId];
uint256 sireId = matron.siringWithId;
if (_resourceToken != address(0)) {
// users must approve enough resourceToken to this contract
// if _resourceToken is registered
// will be checked in mixgenes
ERC20(_resourceToken).transferFrom(msg.sender, address(this), _level * registry.uintOf(UINT_MIX_TALENT));
}
require(_payAndMix(_matronId, sireId, _resourceToken, _level));
}
function _payAndMix(
uint256 _matronId,
uint256 _sireId,
address _resourceToken,
uint256 _level)
internal returns (bool) {
// Grab a reference to the matron in storage.
Apostle storage matron = tokenId2Apostle[_matronId];
Apostle storage sire = tokenId2Apostle[_sireId];
// Check that the matron is a valid apostle.
require(matron.birthTime > 0);
require(sire.birthTime > 0);
// Check that the matron is pregnant, and that its time has come!
require(_isReadyToGiveBirth(matron));
// Grab a reference to the sire in storage.
// uint256 sireId = matron.siringWithId;
// prevent stack too deep error
// Apostle storage sire = tokenId2Apostle[matron.siringWithId];
// Determine the higher generation number of the two parents
uint16 parentGen = matron.generation;
if (sire.generation > matron.generation) {
parentGen = sire.generation;
}
// Call the sooper-sekret, sooper-expensive, gene mixing operation.
(uint256 childGenes, uint256 childTalents) = IGeneScience(registry.addressOf(CONTRACT_GENE_SCIENCE)).mixGenesAndTalents(matron.genes, sire.genes, matron.talents, sire.talents, _resourceToken, _level);
address owner = ERC721(registry.addressOf(SettingIds.CONTRACT_OBJECT_OWNERSHIP)).ownerOf(_matronId);
// Make the new Apostle!
_createApostle(_matronId, matron.siringWithId, parentGen + 1, childGenes, childTalents, owner);
// Clear the reference to sire from the matron (REQUIRED! Having siringWithId
// set is what marks a matron as being pregnant.)
delete matron.siringWithId;
return true;
}
function tokenFallback(address _from, uint256 _value, bytes _data) public {
uint256 autoBirthFee = registry.uintOf(ApostleSettingIds.UINT_AUTOBIRTH_FEE);
uint matronId;
uint sireId;
uint level;
if (msg.sender == registry.addressOf(CONTRACT_RING_ERC20_TOKEN)) {
require(_value >= autoBirthFee, 'not enough to breed.');
ERC223(msg.sender).transfer(registry.addressOf(CONTRACT_REVENUE_POOL), _value, toBytes(_from));
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize)
matronId := mload(add(ptr, 132))
sireId := mload(add(ptr, 164))
}
// All checks passed, apostle gets pregnant!
_breedWith(matronId, sireId);
emit AutoBirth(matronId, uint48(tokenId2Apostle[matronId].cooldownEndTime));
} else if (isValidResourceToken(msg.sender)){
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize)
matronId := mload(add(ptr, 132))
level := mload(add(ptr, 164))
}
require(level > 0 && _value >= level * registry.uintOf(UINT_MIX_TALENT), 'resource for mixing is not enough.');
sireId = tokenId2Apostle[matronId].siringWithId;
// TODO: msg.sender must be valid resource tokens, this is now checked in the implement of IGeneScience.
// better to check add a API in IGeneScience for checking valid msg.sender is one of the resource.
require(_payAndMix(matronId, sireId, msg.sender, level));
}
}
function isValidResourceToken(address _resourceToken) public view returns (bool) {
uint index = ILandBase(registry.addressOf(SettingIds.CONTRACT_LAND_BASE)).resourceToken2RateAttrId(_resourceToken);
return index > 0;
}
/// Anyone can try to kill this Apostle;
function killApostle(uint256 _tokenId) public {
require(tokenId2Apostle[_tokenId].activeTime > 0);
require(defaultLifeTime(_tokenId) < now);
address habergPotionShop = registry.addressOf(CONTRACT_HABERG_POTION_SHOP);
IHabergPotionShop(habergPotionShop).tryKillApostle(_tokenId, msg.sender);
}
function isDead(uint256 _tokenId) public view returns (bool) {
return tokenId2Apostle[_tokenId].birthTime > 0 && tokenId2Apostle[_tokenId].deadTime > 0;
}
function defaultLifeTime(uint256 _tokenId) public view returns (uint256) {
uint256 start = tokenId2Apostle[_tokenId].birthTime;
if (tokenId2Apostle[_tokenId].activeTime > 0) {
start = tokenId2Apostle[_tokenId].activeTime;
}
return start + (tokenId2Apostle[_tokenId].talents >> 248) * (1 weeks);
}
/// IMinerObject
function strengthOf(uint256 _tokenId, address _resourceToken, uint256 _landTokenId) public view returns (uint256) {
uint talents = tokenId2Apostle[_tokenId].talents;
return IGeneScience(registry.addressOf(CONTRACT_GENE_SCIENCE))
.getStrength(talents, _resourceToken, _landTokenId);
}
/// IActivityObject
function activityAdded(uint256 _tokenId, address _activity, address _user) auth public {
// to active the apostle when it do activity the first time
if (tokenId2Apostle[_tokenId].activeTime == 0) {
tokenId2Apostle[_tokenId].activeTime = uint48(now);
emit Unbox(_tokenId, now);
}
}
function activityRemoved(uint256 _tokenId, address _activity, address _user) auth public {
// do nothing.
}
/// IActivity
function activityStopped(uint256 _tokenId) auth public {
// do nothing.
}
function getApostleInfo(uint256 _tokenId) public view returns(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256) {
Apostle storage apostle = tokenId2Apostle[_tokenId];
return (
apostle.genes,
apostle.talents,
apostle.matronId,
apostle.sireId,
uint256(apostle.cooldownIndex),
uint256(apostle.generation),
uint256(apostle.birthTime),
uint256(apostle.activeTime),
uint256(apostle.deadTime),
uint256(apostle.cooldownEndTime)
);
}
function toBytes(address x) public pure returns (bytes b) {
b = new bytes(32);
assembly {mstore(add(b, 32), x)}
}
function _updateCoolDown() internal {
cooldowns[0] = uint32(1 minutes);
cooldowns[1] = uint32(2 minutes);
cooldowns[2] = uint32(5 minutes);
cooldowns[3] = uint32(10 minutes);
cooldowns[4] = uint32(30 minutes);
cooldowns[5] = uint32(1 hours);
cooldowns[6] = uint32(2 hours);
cooldowns[7] = uint32(4 hours);
cooldowns[8] = uint32(8 hours);
cooldowns[9] = uint32(16 hours);
cooldowns[10] = uint32(1 days);
cooldowns[11] = uint32(2 days);
cooldowns[12] = uint32(4 days);
cooldowns[13] = uint32(7 days);
}
function updateGenesAndTalents(uint256 _tokenId, uint256 _genes, uint256 _talents) public auth {
Apostle storage aps = tokenId2Apostle[_tokenId];
aps.genes = _genes;
aps.talents = _talents;
}
function batchUpdate(uint256[] _tokenIds, uint256[] _genesList, uint256[] _talentsList) public auth {
require(_tokenIds.length == _genesList.length && _tokenIds.length == _talentsList.length);
for(uint i = 0; i < _tokenIds.length; i++) {
Apostle storage aps = tokenId2Apostle[_tokenIds[i]];
aps.genes = _genesList[i];
aps.talents = _talentsList[i];
}
}
}
/**
*Submitted for verification at Etherscan.io on 2020-10-28
*/
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
pragma solidity ^0.4.24;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* See https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address _who) public view returns (uint256);
function transfer(address _to, uint256 _value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
pragma solidity ^0.4.24;
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address _owner, address _spender)
public view returns (uint256);
function transferFrom(address _from, address _to, uint256 _value)
public returns (bool);
function approve(address _spender, uint256 _value) public returns (bool);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
// File: @evolutionland/common/contracts/interfaces/ISettingsRegistry.sol
pragma solidity ^0.4.24;
contract ISettingsRegistry {
enum SettingsValueTypes { NONE, UINT, STRING, ADDRESS, BYTES, BOOL, INT }
function uintOf(bytes32 _propertyName) public view returns (uint256);
function stringOf(bytes32 _propertyName) public view returns (string);
function addressOf(bytes32 _propertyName) public view returns (address);
function bytesOf(bytes32 _propertyName) public view returns (bytes);
function boolOf(bytes32 _propertyName) public view returns (bool);
function intOf(bytes32 _propertyName) public view returns (int);
function setUintProperty(bytes32 _propertyName, uint _value) public;
function setStringProperty(bytes32 _propertyName, string _value) public;
function setAddressProperty(bytes32 _propertyName, address _value) public;
function setBytesProperty(bytes32 _propertyName, bytes _value) public;
function setBoolProperty(bytes32 _propertyName, bool _value) public;
function setIntProperty(bytes32 _propertyName, int _value) public;
function getValueTypeOf(bytes32 _propertyName) public view returns (uint /* SettingsValueTypes */ );
event ChangeProperty(bytes32 indexed _propertyName, uint256 _type);
}
// File: @evolutionland/common/contracts/interfaces/IBurnableERC20.sol
pragma solidity ^0.4.23;
contract IBurnableERC20 {
function burn(address _from, uint _value) public;
}
// File: @evolutionland/common/contracts/interfaces/IMintableERC20.sol
pragma solidity ^0.4.23;
contract IMintableERC20 {
function mint(address _to, uint256 _value) public;
}
// File: @evolutionland/common/contracts/interfaces/IAuthority.sol
pragma solidity ^0.4.24;
contract IAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
// File: @evolutionland/common/contracts/DSAuth.sol
pragma solidity ^0.4.24;
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
/**
* @title DSAuth
* @dev The DSAuth contract is reference implement of https://github.com/dapphub/ds-auth
* But in the isAuthorized method, the src from address(this) is remove for safty concern.
*/
contract DSAuth is DSAuthEvents {
IAuthority public authority;
address public owner;
constructor() public {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
emit LogSetOwner(owner);
}
function setAuthority(IAuthority authority_)
public
auth
{
authority = authority_;
emit LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == owner) {
return true;
} else if (authority == IAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
// File: @evolutionland/common/contracts/SettingIds.sol
pragma solidity ^0.4.24;
/**
Id definitions for SettingsRegistry.sol
Can be used in conjunction with the settings registry to get properties
*/
contract SettingIds {
bytes32 public constant CONTRACT_RING_ERC20_TOKEN = "CONTRACT_RING_ERC20_TOKEN";
bytes32 public constant CONTRACT_KTON_ERC20_TOKEN = "CONTRACT_KTON_ERC20_TOKEN";
bytes32 public constant CONTRACT_GOLD_ERC20_TOKEN = "CONTRACT_GOLD_ERC20_TOKEN";
bytes32 public constant CONTRACT_WOOD_ERC20_TOKEN = "CONTRACT_WOOD_ERC20_TOKEN";
bytes32 public constant CONTRACT_WATER_ERC20_TOKEN = "CONTRACT_WATER_ERC20_TOKEN";
bytes32 public constant CONTRACT_FIRE_ERC20_TOKEN = "CONTRACT_FIRE_ERC20_TOKEN";
bytes32 public constant CONTRACT_SOIL_ERC20_TOKEN = "CONTRACT_SOIL_ERC20_TOKEN";
bytes32 public constant CONTRACT_OBJECT_OWNERSHIP = "CONTRACT_OBJECT_OWNERSHIP";
bytes32 public constant CONTRACT_TOKEN_LOCATION = "CONTRACT_TOKEN_LOCATION";
bytes32 public constant CONTRACT_LAND_BASE = "CONTRACT_LAND_BASE";
bytes32 public constant CONTRACT_USER_POINTS = "CONTRACT_USER_POINTS";
bytes32 public constant CONTRACT_INTERSTELLAR_ENCODER = "CONTRACT_INTERSTELLAR_ENCODER";
bytes32 public constant CONTRACT_DIVIDENDS_POOL = "CONTRACT_DIVIDENDS_POOL";
bytes32 public constant CONTRACT_TOKEN_USE = "CONTRACT_TOKEN_USE";
bytes32 public constant CONTRACT_REVENUE_POOL = "CONTRACT_REVENUE_POOL";
bytes32 public constant CONTRACT_ERC721_BRIDGE = "CONTRACT_ERC721_BRIDGE";
bytes32 public constant CONTRACT_PET_BASE = "CONTRACT_PET_BASE";
// Cut owner takes on each auction, measured in basis points (1/100 of a percent).
// this can be considered as transaction fee.
// Values 0-10,000 map to 0%-100%
// set ownerCut to 4%
// ownerCut = 400;
bytes32 public constant UINT_AUCTION_CUT = "UINT_AUCTION_CUT"; // Denominator is 10000
bytes32 public constant UINT_TOKEN_OFFER_CUT = "UINT_TOKEN_OFFER_CUT"; // Denominator is 10000
// Cut referer takes on each auction, measured in basis points (1/100 of a percent).
// which cut from transaction fee.
// Values 0-10,000 map to 0%-100%
// set refererCut to 4%
// refererCut = 400;
bytes32 public constant UINT_REFERER_CUT = "UINT_REFERER_CUT";
bytes32 public constant CONTRACT_LAND_RESOURCE = "CONTRACT_LAND_RESOURCE";
}
// File: contracts/BankSettingIds.sol
pragma solidity ^0.4.24;
contract BankSettingIds is SettingIds {
// depositing X RING for 12 months, interest is about (1 * _unitInterest * X / 10**7) KTON
// default: 1000
bytes32 public constant UINT_BANK_UNIT_INTEREST = "UINT_BANK_UNIT_INTEREST";
// penalty multiplier
// default: 3
bytes32 public constant UINT_BANK_PENALTY_MULTIPLIER = "UINT_BANK_PENALTY_MULTIPLIER";
}
// File: contracts/GringottsBankV2.sol
pragma solidity ^0.4.24;
contract GringottsBank is DSAuth, BankSettingIds {
/*
* Events
*/
event ClaimedTokens(address indexed _token, address indexed _owner, uint _amount);
event NewDeposit(uint256 indexed _depositID, address indexed _depositor, uint _value, uint _month, uint _interest);
event ClaimedDeposit(uint256 indexed _depositID, address indexed _depositor, uint _value, bool isPenalty, uint penaltyAmount);
event TransferDeposit(uint256 indexed _depositID, address indexed _oldDepositor, address indexed _newDepositor);
event BurnAndRedeem(uint256 indexed _depositID, address _depositor, uint48 _months, uint48 _startAt, uint64 _unitInterest, uint128 _value, bytes _data);
/*
* Constants
*/
uint public constant MONTH = 30 * 1 days;
/*
* Structs
*/
struct Deposit {
address depositor;
uint48 months; // Length of time from the deposit's beginning to end (in months), For now, months must >= 1 and <= 36
uint48 startAt; // when player deposit, timestamp in seconds
uint128 value; // amount of ring
uint64 unitInterest;
bool claimed;
}
/*
* Storages
*/
bool private singletonLock = false;
ISettingsRegistry public registry;
mapping (uint256 => Deposit) public deposits;
uint public depositCount;
mapping (address => uint[]) public userDeposits;
// player => totalDepositRING, total number of ring that the player has deposited
mapping (address => uint256) public userTotalDeposit;
/*
* Modifiers
*/
modifier singletonLockCall() {
require(!singletonLock, "Only can call once");
_;
singletonLock = true;
}
modifier canBeStoredWith128Bits(uint256 _value) {
require(_value < 340282366920938463463374607431768211455);
_;
}
modifier canBeStoredWith48Bits(uint256 _value) {
require(_value < 281474976710656);
_;
}
/**
* @dev Bank's constructor which set the token address and unitInterest_
*/
constructor () public {
// initializeContract(_registry);
}
/**
* @dev Same with constructor, but is used and called by storage proxy as logic contract.
* @param _registry - address of SettingsRegistry
*/
function initializeContract(address _registry) public singletonLockCall {
// call Ownable's constructor
owner = msg.sender;
emit LogSetOwner(msg.sender);
registry = ISettingsRegistry(_registry);
}
function getDeposit(uint _id) public view returns (address, uint128, uint128, uint256, uint256, bool ) {
return (deposits[_id].depositor, deposits[_id].value, deposits[_id].months,
deposits[_id].startAt, deposits[_id].unitInterest, deposits[_id].claimed);
}
/**
* @dev ERC223 fallback function, make sure to check the msg.sender is from target token contracts
* @param _from - person who transfer token in for deposits or claim deposit with penalty KTON.
* @param _amount - amount of token.
* @param _data - data which indicate the operations.
*/
function tokenFallback(address _from, uint256 _amount, bytes _data) public {
address ring = registry.addressOf(SettingIds.CONTRACT_RING_ERC20_TOKEN);
address kryptonite = registry.addressOf(SettingIds.CONTRACT_KTON_ERC20_TOKEN);
// deposit entrance
if(ring == msg.sender) {
uint months = bytesToUint256(_data);
_deposit(_from, _amount, months);
}
// Early Redemption entrance
if (kryptonite == msg.sender) {
uint _depositID = bytesToUint256(_data);
require(_amount >= computePenalty(_depositID), "No enough amount of KTON penalty.");
_claimDeposit(_from, _depositID, true, _amount);
// burn the KTON transferred in
IBurnableERC20(kryptonite).burn(address(this), _amount);
}
}
/**
* @dev transfer of deposit from Ethereum network to Darwinia Network, params can be obtained by the function 'getDeposit'
* @param _depositID - ID of deposit.
* @param _data - receiving address of darwinia network.
*/
function burnAndRedeem(uint256 _depositID, bytes _data) public {
bytes32 darwiniaAddress;
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize)
darwiniaAddress := mload(add(ptr, 100))
}
// Check the validity of the deposit
require(deposits[_depositID].claimed == false, "Already claimed");
require(deposits[_depositID].startAt > 0, "Deposit not created.");
require(deposits[_depositID].depositor == msg.sender, "Permission denied");
require(_data.length == 32, "The address (Darwinia Network) must be in a 32 bytes hexadecimal format");
require(darwiniaAddress != bytes32(0x0), "Darwinia Network Address can't be empty");
removeUserDepositsByID(_depositID, msg.sender);
require(deposits[_depositID].value <= userTotalDeposit[msg.sender], "Subtraction overflow");
userTotalDeposit[msg.sender] -= deposits[_depositID].value;
address ring = registry.addressOf(SettingIds.CONTRACT_RING_ERC20_TOKEN);
IBurnableERC20(ring).burn(address(this), deposits[_depositID].value);
emit BurnAndRedeem(
_depositID,
deposits[_depositID].depositor,
deposits[_depositID].months,
deposits[_depositID].startAt,
deposits[_depositID].unitInterest,
deposits[_depositID].value,
_data
);
delete deposits[_depositID];
}
/**
* @dev Deposit for msg sender, require the token approvement ahead.
* @param _amount - amount of token.
* @param _months - the amount of months that the token will be locked in the deposit.
*/
function deposit(uint256 _amount, uint256 _months) public {
deposit(msg.sender, _amount, _months);
}
/**
* @dev Deposit for benificiary, require the token approvement ahead.
* @param _benificiary - benificiary of the deposit, which will get the KTON and RINGs after deposit being claimed.
* @param _amount - amount of token.
* @param _months - the amount of months that the token will be locked in the deposit.
*/
function deposit(address _benificiary, uint256 _amount, uint256 _months) public {
address ring = registry.addressOf(SettingIds.CONTRACT_RING_ERC20_TOKEN);
require(ERC20(ring).transferFrom(msg.sender, address(this), _amount), "RING token tranfer failed.");
_deposit(_benificiary, _amount, _months);
}
function claimDeposit(uint _depositID) public {
_claimDeposit(msg.sender, _depositID, false, 0);
}
function claimDepositWithPenalty(uint _depositID) public {
address kryptonite = ERC20(registry.addressOf(SettingIds.CONTRACT_KTON_ERC20_TOKEN));
uint256 _penalty = computePenalty(_depositID);
require(ERC20(kryptonite).transferFrom(msg.sender, address(this), _penalty));
_claimDeposit(msg.sender, _depositID, true, _penalty);
IBurnableERC20(kryptonite).burn(address(this), _penalty);
}
function transferDeposit(address _benificiary, uint _depositID) public {
require(deposits[_depositID].depositor == msg.sender, "Depositor must be the msg.sender");
require(_benificiary != 0x0, "Benificiary can not be zero");
require(deposits[_depositID].claimed == false, "Already claimed, can not transfer.");
// update the depositor of the deposit.
deposits[_depositID].depositor = _benificiary;
// update the deposit ids of the original user and new user.
removeUserDepositsByID(_depositID, msg.sender);
userDeposits[_benificiary].push(_depositID);
// update the balance of the original depositor and new depositor.
require(deposits[_depositID].value <= userTotalDeposit[msg.sender], "Subtraction overflow");
userTotalDeposit[msg.sender] -= deposits[_depositID].value;
userTotalDeposit[_benificiary] += deposits[_depositID].value;
require(userTotalDeposit[_benificiary] >= deposits[_depositID].value, "Addition overflow");
emit TransferDeposit(_depositID, msg.sender, _benificiary);
}
// normal Redemption, withdraw at maturity
function _claimDeposit(address _depositor, uint _depositID, bool isPenalty, uint _penaltyAmount) internal {
address ring = registry.addressOf(SettingIds.CONTRACT_RING_ERC20_TOKEN);
require(deposits[_depositID].startAt > 0, "Deposit not created.");
require(deposits[_depositID].claimed == false, "Already claimed");
require(deposits[_depositID].depositor == _depositor, "Depositor must match.");
if (isPenalty) {
require(now - deposits[_depositID].startAt < deposits[_depositID].months * MONTH );
} else {
require(now - deposits[_depositID].startAt >= deposits[_depositID].months * MONTH );
}
deposits[_depositID].claimed = true;
userTotalDeposit[_depositor] -= deposits[_depositID].value;
require(ERC20(ring).transfer(_depositor, deposits[_depositID].value));
emit ClaimedDeposit(_depositID, _depositor, deposits[_depositID].value, isPenalty, _penaltyAmount);
}
/**
* @dev deposit actions
* @param _depositor - person who deposits
* @param _value - depositor wants to deposit how many tokens
* @param _month - Length of time from the deposit's beginning to end (in months).
*/
function _deposit(address _depositor, uint _value, uint _month)
canBeStoredWith128Bits(_value) canBeStoredWith128Bits(_month) internal returns (uint _depositId) {
address kryptonite = ERC20(registry.addressOf(SettingIds.CONTRACT_KTON_ERC20_TOKEN));
require( _value > 0 ); // because the _value is pass in from token transfer, token transfer will help check, so there should not be overflow issues.
require( _month <= 36 && _month >= 1 );
_depositId = depositCount;
uint64 _unitInterest = uint64(registry.uintOf(BankSettingIds.UINT_BANK_UNIT_INTEREST));
deposits[_depositId] = Deposit({
depositor: _depositor,
value: uint128(_value),
months: uint48(_month),
startAt: uint48(now),
unitInterest: uint48(_unitInterest),
claimed: false
});
depositCount += 1;
userDeposits[_depositor].push(_depositId);
userTotalDeposit[_depositor] += _value;
require(userTotalDeposit[_depositor] >= _value, "Addition overflow");
// give the player interest immediately
uint interest = computeInterest(_value, _month, _unitInterest);
IMintableERC20(kryptonite).mint(_depositor, interest);
emit NewDeposit(_depositId, _depositor, _value, _month, interest);
}
/**
* @dev compute interst based on deposit amount and deposit time
* @param _value - Amount of ring (in deceimal units)
* @param _month - Length of time from the deposit's beginning to end (in months).
* @param _unitInterest - Parameter of basic interest for deposited RING.(default value is 1000, returns _unitInterest/ 10**7 for one year)
*/
function computeInterest(uint _value, uint _month, uint _unitInterest)
public canBeStoredWith128Bits(_value) canBeStoredWith48Bits(_month) pure returns (uint) {
// these two actually mean the multiplier is 1.015
uint numerator = 67 ** _month;
uint denominator = 66 ** _month;
uint quotient;
uint remainder;
assembly {
quotient := div(numerator, denominator)
remainder := mod(numerator, denominator)
}
// depositing X RING for 12 months, interest is about (1 * _unitInterest * X / 10**7) KTON
// and the multiplier is about 3
// ((quotient - 1) * 1000 + remainder * 1000 / denominator) is 197 when _month is 12.
return (_unitInterest * uint128(_value)) * ((quotient - 1) * 1000 + remainder * 1000 / denominator) / (197 * 10**7);
}
function isClaimRequirePenalty(uint _depositID) public view returns (bool) {
return (deposits[_depositID].startAt > 0 &&
!deposits[_depositID].claimed &&
(now - deposits[_depositID].startAt < deposits[_depositID].months * MONTH ));
}
function computePenalty(uint _depositID) public view returns (uint256) {
require(isClaimRequirePenalty(_depositID), "Claim do not need Penalty.");
uint256 monthsDuration = (now - deposits[_depositID].startAt) / MONTH;
uint256 penalty = registry.uintOf(BankSettingIds.UINT_BANK_PENALTY_MULTIPLIER) *
(computeInterest(deposits[_depositID].value, deposits[_depositID].months, deposits[_depositID].unitInterest) - computeInterest(deposits[_depositID].value, monthsDuration, deposits[_depositID].unitInterest));
return penalty;
}
function getDepositIds(address _user) public view returns(uint256[]) {
return userDeposits[_user];
}
function bytesToUint256(bytes _encodedParam) public pure returns (uint256 a) {
/* solium-disable-next-line security/no-inline-assembly */
assembly {
a := mload(add(_encodedParam, /*BYTES_HEADER_SIZE*/32))
}
}
/// @notice This method can be used by the owner to extract mistakenly
/// sent tokens to this contract.
/// @param _token The address of the token contract that you want to recover
/// set to 0 in case you want to extract ether.
function claimTokens(address _token) public onlyOwner {
if (_token == 0x0) {
owner.transfer(address(this).balance);
return;
}
ERC20 token = ERC20(_token);
uint balance = token.balanceOf(address(this));
token.transfer(owner, balance);
emit ClaimedTokens(_token, owner, balance);
}
function setRegistry(address _registry) public onlyOwner {
registry = ISettingsRegistry(_registry);
}
function removeUserDepositsByID(uint _depositID, address _depositor) private{
// update the deposit ids of the original user and new user.
bool found = false;
for(uint i = 0 ; i < userDeposits[_depositor].length; i++)
{
if (!found && userDeposits[_depositor][i] == _depositID){
found = true;
delete userDeposits[_depositor][i];
}
if (found && i < userDeposits[_depositor].length - 1)
{
// shifts value to left
userDeposits[_depositor][i] = userDeposits[_depositor][i+1];
}
}
delete userDeposits[_depositor][userDeposits[_depositor].length-1];
//reducing the length
userDeposits[_depositor].length--;
}
}
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
pragma solidity ^0.4.24;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* See https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address _who) public view returns (uint256);
function transfer(address _to, uint256 _value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
pragma solidity ^0.4.24;
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address _owner, address _spender)
public view returns (uint256);
function transferFrom(address _from, address _to, uint256 _value)
public returns (bool);
function approve(address _spender, uint256 _value) public returns (bool);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
// File: @evolutionland/common/contracts/interfaces/ISettingsRegistry.sol
pragma solidity ^0.4.24;
contract ISettingsRegistry {
enum SettingsValueTypes { NONE, UINT, STRING, ADDRESS, BYTES, BOOL, INT }
function uintOf(bytes32 _propertyName) public view returns (uint256);
function stringOf(bytes32 _propertyName) public view returns (string);
function addressOf(bytes32 _propertyName) public view returns (address);
function bytesOf(bytes32 _propertyName) public view returns (bytes);
function boolOf(bytes32 _propertyName) public view returns (bool);
function intOf(bytes32 _propertyName) public view returns (int);
function setUintProperty(bytes32 _propertyName, uint _value) public;
function setStringProperty(bytes32 _propertyName, string _value) public;
function setAddressProperty(bytes32 _propertyName, address _value) public;
function setBytesProperty(bytes32 _propertyName, bytes _value) public;
function setBoolProperty(bytes32 _propertyName, bool _value) public;
function setIntProperty(bytes32 _propertyName, int _value) public;
function getValueTypeOf(bytes32 _propertyName) public view returns (uint /* SettingsValueTypes */ );
event ChangeProperty(bytes32 indexed _propertyName, uint256 _type);
}
// File: @evolutionland/common/contracts/interfaces/IBurnableERC20.sol
pragma solidity ^0.4.23;
contract IBurnableERC20 {
function burn(address _from, uint _value) public;
}
// File: @evolutionland/common/contracts/interfaces/IMintableERC20.sol
pragma solidity ^0.4.23;
contract IMintableERC20 {
function mint(address _to, uint256 _value) public;
}
// File: @evolutionland/common/contracts/interfaces/IAuthority.sol
pragma solidity ^0.4.24;
contract IAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
// File: @evolutionland/common/contracts/DSAuth.sol
pragma solidity ^0.4.24;
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
/**
* @title DSAuth
* @dev The DSAuth contract is reference implement of https://github.com/dapphub/ds-auth
* But in the isAuthorized method, the src from address(this) is remove for safty concern.
*/
contract DSAuth is DSAuthEvents {
IAuthority public authority;
address public owner;
constructor() public {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
emit LogSetOwner(owner);
}
function setAuthority(IAuthority authority_)
public
auth
{
authority = authority_;
emit LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == owner) {
return true;
} else if (authority == IAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
// File: @evolutionland/common/contracts/SettingIds.sol
pragma solidity ^0.4.24;
/**
Id definitions for SettingsRegistry.sol
Can be used in conjunction with the settings registry to get properties
*/
contract SettingIds {
bytes32 public constant CONTRACT_RING_ERC20_TOKEN = "CONTRACT_RING_ERC20_TOKEN";
bytes32 public constant CONTRACT_KTON_ERC20_TOKEN = "CONTRACT_KTON_ERC20_TOKEN";
bytes32 public constant CONTRACT_GOLD_ERC20_TOKEN = "CONTRACT_GOLD_ERC20_TOKEN";
bytes32 public constant CONTRACT_WOOD_ERC20_TOKEN = "CONTRACT_WOOD_ERC20_TOKEN";
bytes32 public constant CONTRACT_WATER_ERC20_TOKEN = "CONTRACT_WATER_ERC20_TOKEN";
bytes32 public constant CONTRACT_FIRE_ERC20_TOKEN = "CONTRACT_FIRE_ERC20_TOKEN";
bytes32 public constant CONTRACT_SOIL_ERC20_TOKEN = "CONTRACT_SOIL_ERC20_TOKEN";
bytes32 public constant CONTRACT_OBJECT_OWNERSHIP = "CONTRACT_OBJECT_OWNERSHIP";
bytes32 public constant CONTRACT_TOKEN_LOCATION = "CONTRACT_TOKEN_LOCATION";
bytes32 public constant CONTRACT_LAND_BASE = "CONTRACT_LAND_BASE";
bytes32 public constant CONTRACT_USER_POINTS = "CONTRACT_USER_POINTS";
bytes32 public constant CONTRACT_INTERSTELLAR_ENCODER = "CONTRACT_INTERSTELLAR_ENCODER";
bytes32 public constant CONTRACT_DIVIDENDS_POOL = "CONTRACT_DIVIDENDS_POOL";
bytes32 public constant CONTRACT_TOKEN_USE = "CONTRACT_TOKEN_USE";
bytes32 public constant CONTRACT_REVENUE_POOL = "CONTRACT_REVENUE_POOL";
bytes32 public constant CONTRACT_ERC721_BRIDGE = "CONTRACT_ERC721_BRIDGE";
bytes32 public constant CONTRACT_PET_BASE = "CONTRACT_PET_BASE";
// Cut owner takes on each auction, measured in basis points (1/100 of a percent).
// this can be considered as transaction fee.
// Values 0-10,000 map to 0%-100%
// set ownerCut to 4%
// ownerCut = 400;
bytes32 public constant UINT_AUCTION_CUT = "UINT_AUCTION_CUT"; // Denominator is 10000
bytes32 public constant UINT_TOKEN_OFFER_CUT = "UINT_TOKEN_OFFER_CUT"; // Denominator is 10000
// Cut referer takes on each auction, measured in basis points (1/100 of a percent).
// which cut from transaction fee.
// Values 0-10,000 map to 0%-100%
// set refererCut to 4%
// refererCut = 400;
bytes32 public constant UINT_REFERER_CUT = "UINT_REFERER_CUT";
bytes32 public constant CONTRACT_LAND_RESOURCE = "CONTRACT_LAND_RESOURCE";
}
// File: contracts/BankSettingIds.sol
pragma solidity ^0.4.24;
contract BankSettingIds is SettingIds {
// depositing X RING for 12 months, interest is about (1 * _unitInterest * X / 10**7) KTON
// default: 1000
bytes32 public constant UINT_BANK_UNIT_INTEREST = "UINT_BANK_UNIT_INTEREST";
// penalty multiplier
// default: 3
bytes32 public constant UINT_BANK_PENALTY_MULTIPLIER = "UINT_BANK_PENALTY_MULTIPLIER";
}
// File: contracts/GringottsBank.sol
pragma solidity ^0.4.24;
contract GringottsBank is DSAuth, BankSettingIds {
/*
* Events
*/
event ClaimedTokens(address indexed _token, address indexed _owner, uint _amount);
event NewDeposit(uint256 indexed _depositID, address indexed _depositor, uint _value, uint _month, uint _interest);
event ClaimedDeposit(uint256 indexed _depositID, address indexed _depositor, uint _value, bool isPenalty, uint penaltyAmount);
event TransferDeposit(uint256 indexed _depositID, address indexed _oldDepositor, address indexed _newDepositor);
/*
* Constants
*/
uint public constant MONTH = 30 * 1 days;
/*
* Structs
*/
struct Deposit {
address depositor;
uint48 months; // Length of time from the deposit's beginning to end (in months), For now, months must >= 1 and <= 36
uint48 startAt; // when player deposit, timestamp in seconds
uint128 value; // amount of ring
uint64 unitInterest;
bool claimed;
}
/*
* Storages
*/
bool private singletonLock = false;
ISettingsRegistry public registry;
mapping (uint256 => Deposit) public deposits;
uint public depositCount;
mapping (address => uint[]) public userDeposits;
// player => totalDepositRING, total number of ring that the player has deposited
mapping (address => uint256) public userTotalDeposit;
/*
* Modifiers
*/
modifier singletonLockCall() {
require(!singletonLock, "Only can call once");
_;
singletonLock = true;
}
modifier canBeStoredWith128Bits(uint256 _value) {
require(_value < 340282366920938463463374607431768211455);
_;
}
modifier canBeStoredWith48Bits(uint256 _value) {
require(_value < 281474976710656);
_;
}
/**
* @dev Bank's constructor which set the token address and unitInterest_
*/
constructor () public {
// initializeContract(_registry);
}
/**
* @dev Same with constructor, but is used and called by storage proxy as logic contract.
* @param _registry - address of SettingsRegistry
*/
function initializeContract(address _registry) public singletonLockCall {
// call Ownable's constructor
owner = msg.sender;
emit LogSetOwner(msg.sender);
registry = ISettingsRegistry(_registry);
}
function getDeposit(uint _id) public view returns (address, uint128, uint128, uint256, uint256, bool ) {
return (deposits[_id].depositor, deposits[_id].value, deposits[_id].months,
deposits[_id].startAt, deposits[_id].unitInterest, deposits[_id].claimed);
}
/**
* @dev ERC223 fallback function, make sure to check the msg.sender is from target token contracts
* @param _from - person who transfer token in for deposits or claim deposit with penalty KTON.
* @param _amount - amount of token.
* @param _data - data which indicate the operations.
*/
function tokenFallback(address _from, uint256 _amount, bytes _data) public {
address ring = registry.addressOf(SettingIds.CONTRACT_RING_ERC20_TOKEN);
address kryptonite = registry.addressOf(SettingIds.CONTRACT_KTON_ERC20_TOKEN);
// deposit entrance
if(ring == msg.sender) {
uint months = bytesToUint256(_data);
_deposit(_from, _amount, months);
}
// Early Redemption entrance
if (kryptonite == msg.sender) {
uint _depositID = bytesToUint256(_data);
require(_amount >= computePenalty(_depositID), "No enough amount of KTON penalty.");
_claimDeposit(_from, _depositID, true, _amount);
// burn the KTON transferred in
IBurnableERC20(kryptonite).burn(address(this), _amount);
}
}
/**
* @dev Deposit for msg sender, require the token approvement ahead.
* @param _amount - amount of token.
* @param _months - the amount of months that the token will be locked in the deposit.
*/
function deposit(uint256 _amount, uint256 _months) public {
deposit(msg.sender, _amount, _months);
}
/**
* @dev Deposit for benificiary, require the token approvement ahead.
* @param _benificiary - benificiary of the deposit, which will get the KTON and RINGs after deposit being claimed.
* @param _amount - amount of token.
* @param _months - the amount of months that the token will be locked in the deposit.
*/
function deposit(address _benificiary, uint256 _amount, uint256 _months) public {
address ring = registry.addressOf(SettingIds.CONTRACT_RING_ERC20_TOKEN);
require(ERC20(ring).transferFrom(msg.sender, address(this), _amount), "RING token tranfer failed.");
_deposit(_benificiary, _amount, _months);
}
function claimDeposit(uint _depositID) public {
_claimDeposit(msg.sender, _depositID, false, 0);
}
function claimDepositWithPenalty(uint _depositID) public {
address kryptonite = ERC20(registry.addressOf(SettingIds.CONTRACT_KTON_ERC20_TOKEN));
uint256 _penalty = computePenalty(_depositID);
require(ERC20(kryptonite).transferFrom(msg.sender, address(this), _penalty));
_claimDeposit(msg.sender, _depositID, true, _penalty);
IBurnableERC20(kryptonite).burn(address(this), _penalty);
}
function transferDeposit(address _benificiary, uint _depositID) public {
require(deposits[_depositID].depositor == msg.sender, "Depositor must be the msg.sender");
require(_benificiary != 0x0, "Benificiary can not be zero");
require(deposits[_depositID].claimed == false, "Already claimed, can not transfer.");
// update the depositor of the deposit.
deposits[_depositID].depositor = _benificiary;
// update the deposit ids of the original user and new user.
bool found = false;
for(uint i = 0 ; i < userDeposits[msg.sender].length; i++)
{
if (!found && userDeposits[msg.sender][i] == _depositID){
found = true;
delete userDeposits[msg.sender][i];
}
if (found && i < userDeposits[msg.sender].length - 1)
{
// shifts value to left
userDeposits[msg.sender][i] = userDeposits[msg.sender][i+1];
}
}
delete userDeposits[msg.sender][userDeposits[msg.sender].length-1];
//reducing the length
userDeposits[msg.sender].length--;
userDeposits[_benificiary].push(_depositID);
// update the balance of the original depositor and new depositor.
userTotalDeposit[msg.sender] -= deposits[_depositID].value;
userTotalDeposit[_benificiary] += deposits[_depositID].value;
emit TransferDeposit(_depositID, msg.sender, _benificiary);
}
// normal Redemption, withdraw at maturity
function _claimDeposit(address _depositor, uint _depositID, bool isPenalty, uint _penaltyAmount) internal {
address ring = registry.addressOf(SettingIds.CONTRACT_RING_ERC20_TOKEN);
require(deposits[_depositID].startAt > 0, "Deposit not created.");
require(deposits[_depositID].claimed == false, "Already claimed");
require(deposits[_depositID].depositor == _depositor, "Depositor must match.");
if (isPenalty) {
require(now - deposits[_depositID].startAt < deposits[_depositID].months * MONTH );
} else {
require(now - deposits[_depositID].startAt >= deposits[_depositID].months * MONTH );
}
deposits[_depositID].claimed = true;
userTotalDeposit[_depositor] -= deposits[_depositID].value;
require(ERC20(ring).transfer(_depositor, deposits[_depositID].value));
emit ClaimedDeposit(_depositID, _depositor, deposits[_depositID].value, isPenalty, _penaltyAmount);
}
/**
* @dev deposit actions
* @param _depositor - person who deposits
* @param _value - depositor wants to deposit how many tokens
* @param _month - Length of time from the deposit's beginning to end (in months).
*/
function _deposit(address _depositor, uint _value, uint _month)
canBeStoredWith128Bits(_value) canBeStoredWith128Bits(_month) internal returns (uint _depositId) {
address kryptonite = ERC20(registry.addressOf(SettingIds.CONTRACT_KTON_ERC20_TOKEN));
require( _value > 0 ); // because the _value is pass in from token transfer, token transfer will help check, so there should not be overflow issues.
require( _month <= 36 && _month >= 1 );
_depositId = depositCount;
uint64 _unitInterest = uint64(registry.uintOf(BankSettingIds.UINT_BANK_UNIT_INTEREST));
deposits[_depositId] = Deposit({
depositor: _depositor,
value: uint128(_value),
months: uint48(_month),
startAt: uint48(now),
unitInterest: uint48(_unitInterest),
claimed: false
});
depositCount += 1;
userDeposits[_depositor].push(_depositId);
userTotalDeposit[_depositor] += _value;
// give the player interest immediately
uint interest = computeInterest(_value, _month, _unitInterest);
IMintableERC20(kryptonite).mint(_depositor, interest);
emit NewDeposit(_depositId, _depositor, _value, _month, interest);
}
/**
* @dev compute interst based on deposit amount and deposit time
* @param _value - Amount of ring (in deceimal units)
* @param _month - Length of time from the deposit's beginning to end (in months).
* @param _unitInterest - Parameter of basic interest for deposited RING.(default value is 1000, returns _unitInterest/ 10**7 for one year)
*/
function computeInterest(uint _value, uint _month, uint _unitInterest)
public canBeStoredWith128Bits(_value) canBeStoredWith48Bits(_month) pure returns (uint) {
// these two actually mean the multiplier is 1.015
uint numerator = 67 ** _month;
uint denominator = 66 ** _month;
uint quotient;
uint remainder;
assembly {
quotient := div(numerator, denominator)
remainder := mod(numerator, denominator)
}
// depositing X RING for 12 months, interest is about (1 * _unitInterest * X / 10**7) KTON
// and the multiplier is about 3
// ((quotient - 1) * 1000 + remainder * 1000 / denominator) is 197 when _month is 12.
return (_unitInterest * uint128(_value)) * ((quotient - 1) * 1000 + remainder * 1000 / denominator) / (197 * 10**7);
}
function isClaimRequirePenalty(uint _depositID) public view returns (bool) {
return (deposits[_depositID].startAt > 0 &&
!deposits[_depositID].claimed &&
(now - deposits[_depositID].startAt < deposits[_depositID].months * MONTH ));
}
function computePenalty(uint _depositID) public view returns (uint256) {
require(isClaimRequirePenalty(_depositID), "Claim do not need Penalty.");
uint256 monthsDuration = (now - deposits[_depositID].startAt) / MONTH;
uint256 penalty = registry.uintOf(BankSettingIds.UINT_BANK_PENALTY_MULTIPLIER) *
(computeInterest(deposits[_depositID].value, deposits[_depositID].months, deposits[_depositID].unitInterest) - computeInterest(deposits[_depositID].value, monthsDuration, deposits[_depositID].unitInterest));
return penalty;
}
function getDepositIds(address _user) public view returns(uint256[]) {
return userDeposits[_user];
}
function bytesToUint256(bytes _encodedParam) public pure returns (uint256 a) {
/* solium-disable-next-line security/no-inline-assembly */
assembly {
a := mload(add(_encodedParam, /*BYTES_HEADER_SIZE*/32))
}
}
/// @notice This method can be used by the owner to extract mistakenly
/// sent tokens to this contract.
/// @param _token The address of the token contract that you want to recover
/// set to 0 in case you want to extract ether.
function claimTokens(address _token) public onlyOwner {
if (_token == 0x0) {
owner.transfer(address(this).balance);
return;
}
ERC20 token = ERC20(_token);
uint balance = token.balanceOf(address(this));
token.transfer(owner, balance);
emit ClaimedTokens(_token, owner, balance);
}
function setRegistry(address _registry) public onlyOwner {
registry = ISettingsRegistry(_registry);
}
}
// File: openzeppelin-solidity/contracts/ownership/Ownable.sol
pragma solidity ^0.4.24;
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to relinquish control of the contract.
* @notice Renouncing to ownership will leave the contract without an owner.
* It will not be possible to call the functions with the `onlyOwner`
* modifier anymore.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipRenounced(owner);
owner = address(0);
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function transferOwnership(address _newOwner) public onlyOwner {
_transferOwnership(_newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function _transferOwnership(address _newOwner) internal {
require(_newOwner != address(0));
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}
// File: contracts/interfaces/IInterstellarEncoderV3.sol
pragma solidity ^0.4.24;
contract IInterstellarEncoderV3 {
uint256 constant CLEAR_HIGH = 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;
uint256 public constant MAGIC_NUMBER = 42; // Interstellar Encoding Magic Number.
uint256 public constant CHAIN_ID = 1; // Ethereum mainet.
uint256 public constant CURRENT_LAND = 1; // 1 is Atlantis, 0 is NaN.
enum ObjectClass {
NaN,
LAND,
APOSTLE,
OBJECT_CLASS_COUNT
}
function registerNewObjectClass(address _objectContract, uint8 objectClass) public;
function encodeTokenId(address _tokenAddress, uint8 _objectClass, uint128 _objectIndex) public view returns (uint256 _tokenId);
function encodeTokenIdForObjectContract(
address _tokenAddress, address _objectContract, uint128 _objectId) public view returns (uint256 _tokenId);
function encodeTokenIdForOuterObjectContract(
address _objectContract, address nftAddress, address _originNftAddress, uint128 _objectId, uint16 _producerId, uint8 _convertType) public view returns (uint256);
function getContractAddress(uint256 _tokenId) public view returns (address);
function getObjectId(uint256 _tokenId) public view returns (uint128 _objectId);
function getObjectClass(uint256 _tokenId) public view returns (uint8);
function getObjectAddress(uint256 _tokenId) public view returns (address);
function getProducerId(uint256 _tokenId) public view returns (uint16);
function getOriginAddress(uint256 _tokenId) public view returns (address);
}
// File: contracts/InterstellarEncoderV3.sol
pragma solidity ^0.4.24;
// TODO: upgrade.
contract InterstellarEncoderV3 is IInterstellarEncoderV3, Ownable {
// [magic_number, chain_id, contract_id <2>, origin_chain_id, origin_contract_id<2>, object_class, convert_type, <6>, land, <128>]
mapping(uint8 => address) public ownershipId2Address;
mapping(address => uint8) public ownershipAddress2Id;
mapping(address => uint8) public classAddress2Id; // class
// extended since V2
mapping(uint8 => address) public classId2Address;
function encodeTokenId(address _tokenAddress, uint8 _objectClass, uint128 _objectId) public view returns (uint256 _tokenId) {
uint16 contractId = ownershipAddress2Id[_tokenAddress];
require(ownershipAddress2Id[_tokenAddress] > 0, "Contract address does not exist");
_tokenId = (MAGIC_NUMBER << 248) + (CHAIN_ID << 240) + (uint256(contractId) << 224)
+ (CHAIN_ID << 216) + (uint256(contractId) << 200) + (uint256(_objectClass) << 192) + (CURRENT_LAND << 128) + uint256(_objectId);
}
function encodeTokenIdForOuter(
address _nftAddress, address _originNftAddress, uint8 _objectClass, uint128 _objectId, uint16 _producerId, uint8 _convertType) public view returns (uint256) {
uint16 contractId = ownershipAddress2Id[_nftAddress];
uint16 originContractId = ownershipAddress2Id[_originNftAddress];
require(contractId > 0 && originContractId > 0 && _producerId > 0, "Contract address does not exist");
uint256 tokenId = (MAGIC_NUMBER << 248) + (CHAIN_ID << 240) + (uint256(contractId) << 224)
+ (CHAIN_ID << 216) + (uint256(originContractId) << 200) + (uint256(_objectClass) << 192) + (uint256(_convertType) << 184)+ (uint256(_producerId) << 128) + uint256(_objectId);
return tokenId;
}
// TODO; newly added
// @param _tokenAddress - objectOwnership
// @param _objectContract - xxxBase contract
function encodeTokenIdForOuterObjectContract(
address _objectContract, address _nftAddress, address _originNftAddress, uint128 _objectId, uint16 _producerId, uint8 _convertType) public view returns (uint256) {
require (classAddress2Id[_objectContract] > 0, "Object class for this object contract does not exist.");
return encodeTokenIdForOuter(_nftAddress, _originNftAddress, classAddress2Id[_objectContract], _objectId, _producerId, _convertType);
}
// TODO; newly added
function encodeTokenIdForObjectContract(
address _tokenAddress, address _objectContract, uint128 _objectId) public view returns (uint256 _tokenId) {
require (classAddress2Id[_objectContract] > 0, "Object class for this object contract does not exist.");
_tokenId = encodeTokenId(_tokenAddress, classAddress2Id[_objectContract], _objectId);
}
function registerNewOwnershipContract(address _nftAddress, uint8 _nftId) public onlyOwner {
ownershipAddress2Id[_nftAddress] = _nftId;
ownershipId2Address[_nftId] = _nftAddress;
}
function registerNewObjectClass(address _objectContract, uint8 _objectClass) public onlyOwner {
classAddress2Id[_objectContract] = _objectClass;
classId2Address[_objectClass] = _objectContract;
}
function getProducerId(uint256 _tokenId) public view returns (uint16) {
return uint16((_tokenId >> 128) & 0xff);
}
function getContractAddress(uint256 _tokenId) public view returns (address) {
return ownershipId2Address[uint8((_tokenId >> 240) & 0xff)];
}
function getObjectId(uint256 _tokenId) public view returns (uint128 _objectId) {
return uint128(_tokenId & CLEAR_HIGH);
}
function getObjectClass(uint256 _tokenId) public view returns (uint8) {
return uint8((_tokenId << 56) >> 248);
}
function getObjectAddress(uint256 _tokenId) public view returns (address) {
return classId2Address[uint8((_tokenId << 56) >> 248)];
}
// TODO; newly added
function getOriginAddress(uint256 _tokenId) public view returns (address) {
uint8 originContractId = uint8((_tokenId >> 200) & 0xff);
return ownershipId2Address[originContractId];
}
}
// File: openzeppelin-solidity/contracts/introspection/ERC165.sol
pragma solidity ^0.4.24;
/**
* @title ERC165
* @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
*/
interface ERC165 {
/**
* @notice Query if a contract implements an interface
* @param _interfaceId The interface identifier, as specified in ERC-165
* @dev Interface identification is specified in ERC-165. This function
* uses less than 30,000 gas.
*/
function supportsInterface(bytes4 _interfaceId)
external
view
returns (bool);
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721Basic.sol
pragma solidity ^0.4.24;
/**
* @title ERC721 Non-Fungible Token Standard basic interface
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Basic is ERC165 {
bytes4 internal constant InterfaceId_ERC721 = 0x80ac58cd;
/*
* 0x80ac58cd ===
* bytes4(keccak256('balanceOf(address)')) ^
* bytes4(keccak256('ownerOf(uint256)')) ^
* bytes4(keccak256('approve(address,uint256)')) ^
* bytes4(keccak256('getApproved(uint256)')) ^
* bytes4(keccak256('setApprovalForAll(address,bool)')) ^
* bytes4(keccak256('isApprovedForAll(address,address)')) ^
* bytes4(keccak256('transferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
*/
bytes4 internal constant InterfaceId_ERC721Exists = 0x4f558e79;
/*
* 0x4f558e79 ===
* bytes4(keccak256('exists(uint256)'))
*/
bytes4 internal constant InterfaceId_ERC721Enumerable = 0x780e9d63;
/**
* 0x780e9d63 ===
* bytes4(keccak256('totalSupply()')) ^
* bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^
* bytes4(keccak256('tokenByIndex(uint256)'))
*/
bytes4 internal constant InterfaceId_ERC721Metadata = 0x5b5e139f;
/**
* 0x5b5e139f ===
* bytes4(keccak256('name()')) ^
* bytes4(keccak256('symbol()')) ^
* bytes4(keccak256('tokenURI(uint256)'))
*/
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) public view returns (uint256 _balance);
function ownerOf(uint256 _tokenId) public view returns (address _owner);
function exists(uint256 _tokenId) public view returns (bool _exists);
function approve(address _to, uint256 _tokenId) public;
function getApproved(uint256 _tokenId)
public view returns (address _operator);
function setApprovalForAll(address _operator, bool _approved) public;
function isApprovedForAll(address _owner, address _operator)
public view returns (bool);
function transferFrom(address _from, address _to, uint256 _tokenId) public;
function safeTransferFrom(address _from, address _to, uint256 _tokenId)
public;
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes _data
)
public;
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721.sol
pragma solidity ^0.4.24;
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Enumerable is ERC721Basic {
function totalSupply() public view returns (uint256);
function tokenOfOwnerByIndex(
address _owner,
uint256 _index
)
public
view
returns (uint256 _tokenId);
function tokenByIndex(uint256 _index) public view returns (uint256);
}
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Metadata is ERC721Basic {
function name() external view returns (string _name);
function symbol() external view returns (string _symbol);
function tokenURI(uint256 _tokenId) public view returns (string);
}
/**
* @title ERC-721 Non-Fungible Token Standard, full implementation interface
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata {
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721Receiver.sol
pragma solidity ^0.4.24;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
contract ERC721Receiver {
/**
* @dev Magic value to be returned upon successful reception of an NFT
* Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`,
* which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
*/
bytes4 internal constant ERC721_RECEIVED = 0x150b7a02;
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a `safetransfer`. This function MAY throw to revert and reject the
* transfer. Return of other than the magic value MUST result in the
* transaction being reverted.
* Note: the contract address is always the message sender.
* @param _operator The address which called `safeTransferFrom` function
* @param _from The address which previously owned the token
* @param _tokenId The NFT identifier which is being transferred
* @param _data Additional data with no specified format
* @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
*/
function onERC721Received(
address _operator,
address _from,
uint256 _tokenId,
bytes _data
)
public
returns(bytes4);
}
// File: openzeppelin-solidity/contracts/math/SafeMath.sol
pragma solidity ^0.4.24;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
// Gas optimization: this is cheaper than asserting 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (_a == 0) {
return 0;
}
c = _a * _b;
assert(c / _a == _b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
// assert(_b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = _a / _b;
// assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
return _a / _b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
assert(_b <= _a);
return _a - _b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
c = _a + _b;
assert(c >= _a);
return c;
}
}
// File: openzeppelin-solidity/contracts/AddressUtils.sol
pragma solidity ^0.4.24;
/**
* Utility library of inline functions on addresses
*/
library AddressUtils {
/**
* Returns whether the target address is a contract
* @dev This function will return false if invoked during the constructor of a contract,
* as the code is not actually created until after the constructor finishes.
* @param _addr address to check
* @return whether the target address is a contract
*/
function isContract(address _addr) internal view returns (bool) {
uint256 size;
// XXX Currently there is no better way to check if there is a contract in an address
// than to check the size of the code at that address.
// See https://ethereum.stackexchange.com/a/14016/36603
// for more details about how this works.
// TODO Check this again before the Serenity release, because all addresses will be
// contracts then.
// solium-disable-next-line security/no-inline-assembly
assembly { size := extcodesize(_addr) }
return size > 0;
}
}
// File: openzeppelin-solidity/contracts/introspection/SupportsInterfaceWithLookup.sol
pragma solidity ^0.4.24;
/**
* @title SupportsInterfaceWithLookup
* @author Matt Condon (@shrugs)
* @dev Implements ERC165 using a lookup table.
*/
contract SupportsInterfaceWithLookup is ERC165 {
bytes4 public constant InterfaceId_ERC165 = 0x01ffc9a7;
/**
* 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)'))
*/
/**
* @dev a mapping of interface id to whether or not it's supported
*/
mapping(bytes4 => bool) internal supportedInterfaces;
/**
* @dev A contract implementing SupportsInterfaceWithLookup
* implement ERC165 itself
*/
constructor()
public
{
_registerInterface(InterfaceId_ERC165);
}
/**
* @dev implement supportsInterface(bytes4) using a lookup table
*/
function supportsInterface(bytes4 _interfaceId)
external
view
returns (bool)
{
return supportedInterfaces[_interfaceId];
}
/**
* @dev private method for registering an interface
*/
function _registerInterface(bytes4 _interfaceId)
internal
{
require(_interfaceId != 0xffffffff);
supportedInterfaces[_interfaceId] = true;
}
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721BasicToken.sol
pragma solidity ^0.4.24;
/**
* @title ERC721 Non-Fungible Token Standard basic implementation
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic {
using SafeMath for uint256;
using AddressUtils for address;
// Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
// which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
bytes4 private constant ERC721_RECEIVED = 0x150b7a02;
// Mapping from token ID to owner
mapping (uint256 => address) internal tokenOwner;
// Mapping from token ID to approved address
mapping (uint256 => address) internal tokenApprovals;
// Mapping from owner to number of owned token
mapping (address => uint256) internal ownedTokensCount;
// Mapping from owner to operator approvals
mapping (address => mapping (address => bool)) internal operatorApprovals;
constructor()
public
{
// register the supported interfaces to conform to ERC721 via ERC165
_registerInterface(InterfaceId_ERC721);
_registerInterface(InterfaceId_ERC721Exists);
}
/**
* @dev Gets the balance of the specified address
* @param _owner address to query the balance of
* @return uint256 representing the amount owned by the passed address
*/
function balanceOf(address _owner) public view returns (uint256) {
require(_owner != address(0));
return ownedTokensCount[_owner];
}
/**
* @dev Gets the owner of the specified token ID
* @param _tokenId uint256 ID of the token to query the owner of
* @return owner address currently marked as the owner of the given token ID
*/
function ownerOf(uint256 _tokenId) public view returns (address) {
address owner = tokenOwner[_tokenId];
require(owner != address(0));
return owner;
}
/**
* @dev Returns whether the specified token exists
* @param _tokenId uint256 ID of the token to query the existence of
* @return whether the token exists
*/
function exists(uint256 _tokenId) public view returns (bool) {
address owner = tokenOwner[_tokenId];
return owner != address(0);
}
/**
* @dev Approves another address to transfer the given token ID
* The zero address indicates there is no approved address.
* There can only be one approved address per token at a given time.
* Can only be called by the token owner or an approved operator.
* @param _to address to be approved for the given token ID
* @param _tokenId uint256 ID of the token to be approved
*/
function approve(address _to, uint256 _tokenId) public {
address owner = ownerOf(_tokenId);
require(_to != owner);
require(msg.sender == owner || isApprovedForAll(owner, msg.sender));
tokenApprovals[_tokenId] = _to;
emit Approval(owner, _to, _tokenId);
}
/**
* @dev Gets the approved address for a token ID, or zero if no address set
* @param _tokenId uint256 ID of the token to query the approval of
* @return address currently approved for the given token ID
*/
function getApproved(uint256 _tokenId) public view returns (address) {
return tokenApprovals[_tokenId];
}
/**
* @dev Sets or unsets the approval of a given operator
* An operator is allowed to transfer all tokens of the sender on their behalf
* @param _to operator address to set the approval
* @param _approved representing the status of the approval to be set
*/
function setApprovalForAll(address _to, bool _approved) public {
require(_to != msg.sender);
operatorApprovals[msg.sender][_to] = _approved;
emit ApprovalForAll(msg.sender, _to, _approved);
}
/**
* @dev Tells whether an operator is approved by a given owner
* @param _owner owner address which you want to query the approval of
* @param _operator operator address which you want to query the approval of
* @return bool whether the given operator is approved by the given owner
*/
function isApprovedForAll(
address _owner,
address _operator
)
public
view
returns (bool)
{
return operatorApprovals[_owner][_operator];
}
/**
* @dev Transfers the ownership of a given token ID to another address
* Usage of this method is discouraged, use `safeTransferFrom` whenever possible
* Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
*/
function transferFrom(
address _from,
address _to,
uint256 _tokenId
)
public
{
require(isApprovedOrOwner(msg.sender, _tokenId));
require(_from != address(0));
require(_to != address(0));
clearApproval(_from, _tokenId);
removeTokenFrom(_from, _tokenId);
addTokenTo(_to, _tokenId);
emit Transfer(_from, _to, _tokenId);
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
*
* Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
*/
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
)
public
{
// solium-disable-next-line arg-overflow
safeTransferFrom(_from, _to, _tokenId, "");
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
* Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
* @param _data bytes data to send along with a safe transfer check
*/
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes _data
)
public
{
transferFrom(_from, _to, _tokenId);
// solium-disable-next-line arg-overflow
require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data));
}
/**
* @dev Returns whether the given spender can transfer a given token ID
* @param _spender address of the spender to query
* @param _tokenId uint256 ID of the token to be transferred
* @return bool whether the msg.sender is approved for the given token ID,
* is an operator of the owner, or is the owner of the token
*/
function isApprovedOrOwner(
address _spender,
uint256 _tokenId
)
internal
view
returns (bool)
{
address owner = ownerOf(_tokenId);
// Disable solium check because of
// https://github.com/duaraghav8/Solium/issues/175
// solium-disable-next-line operator-whitespace
return (
_spender == owner ||
getApproved(_tokenId) == _spender ||
isApprovedForAll(owner, _spender)
);
}
/**
* @dev Internal function to mint a new token
* Reverts if the given token ID already exists
* @param _to The address that will own the minted token
* @param _tokenId uint256 ID of the token to be minted by the msg.sender
*/
function _mint(address _to, uint256 _tokenId) internal {
require(_to != address(0));
addTokenTo(_to, _tokenId);
emit Transfer(address(0), _to, _tokenId);
}
/**
* @dev Internal function to burn a specific token
* Reverts if the token does not exist
* @param _tokenId uint256 ID of the token being burned by the msg.sender
*/
function _burn(address _owner, uint256 _tokenId) internal {
clearApproval(_owner, _tokenId);
removeTokenFrom(_owner, _tokenId);
emit Transfer(_owner, address(0), _tokenId);
}
/**
* @dev Internal function to clear current approval of a given token ID
* Reverts if the given address is not indeed the owner of the token
* @param _owner owner of the token
* @param _tokenId uint256 ID of the token to be transferred
*/
function clearApproval(address _owner, uint256 _tokenId) internal {
require(ownerOf(_tokenId) == _owner);
if (tokenApprovals[_tokenId] != address(0)) {
tokenApprovals[_tokenId] = address(0);
}
}
/**
* @dev Internal function to add a token ID to the list of a given address
* @param _to address representing the new owner of the given token ID
* @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function addTokenTo(address _to, uint256 _tokenId) internal {
require(tokenOwner[_tokenId] == address(0));
tokenOwner[_tokenId] = _to;
ownedTokensCount[_to] = ownedTokensCount[_to].add(1);
}
/**
* @dev Internal function to remove a token ID from the list of a given address
* @param _from address representing the previous owner of the given token ID
* @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function removeTokenFrom(address _from, uint256 _tokenId) internal {
require(ownerOf(_tokenId) == _from);
ownedTokensCount[_from] = ownedTokensCount[_from].sub(1);
tokenOwner[_tokenId] = address(0);
}
/**
* @dev Internal function to invoke `onERC721Received` on a target address
* The call is not executed if the target address is not a contract
* @param _from address representing the previous owner of the given token ID
* @param _to target address that will receive the tokens
* @param _tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return whether the call correctly returned the expected magic value
*/
function checkAndCallSafeTransfer(
address _from,
address _to,
uint256 _tokenId,
bytes _data
)
internal
returns (bool)
{
if (!_to.isContract()) {
return true;
}
bytes4 retval = ERC721Receiver(_to).onERC721Received(
msg.sender, _from, _tokenId, _data);
return (retval == ERC721_RECEIVED);
}
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721Token.sol
pragma solidity ^0.4.24;
/**
* @title Full ERC721 Token
* This implementation includes all the required and some optional functionality of the ERC721 standard
* Moreover, it includes approve all functionality using operator terminology
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Token is SupportsInterfaceWithLookup, ERC721BasicToken, ERC721 {
// Token name
string internal name_;
// Token symbol
string internal symbol_;
// Mapping from owner to list of owned token IDs
mapping(address => uint256[]) internal ownedTokens;
// Mapping from token ID to index of the owner tokens list
mapping(uint256 => uint256) internal ownedTokensIndex;
// Array with all token ids, used for enumeration
uint256[] internal allTokens;
// Mapping from token id to position in the allTokens array
mapping(uint256 => uint256) internal allTokensIndex;
// Optional mapping for token URIs
mapping(uint256 => string) internal tokenURIs;
/**
* @dev Constructor function
*/
constructor(string _name, string _symbol) public {
name_ = _name;
symbol_ = _symbol;
// register the supported interfaces to conform to ERC721 via ERC165
_registerInterface(InterfaceId_ERC721Enumerable);
_registerInterface(InterfaceId_ERC721Metadata);
}
/**
* @dev Gets the token name
* @return string representing the token name
*/
function name() external view returns (string) {
return name_;
}
/**
* @dev Gets the token symbol
* @return string representing the token symbol
*/
function symbol() external view returns (string) {
return symbol_;
}
/**
* @dev Returns an URI for a given token ID
* Throws if the token ID does not exist. May return an empty string.
* @param _tokenId uint256 ID of the token to query
*/
function tokenURI(uint256 _tokenId) public view returns (string) {
require(exists(_tokenId));
return tokenURIs[_tokenId];
}
/**
* @dev Gets the token ID at a given index of the tokens list of the requested owner
* @param _owner address owning the tokens list to be accessed
* @param _index uint256 representing the index to be accessed of the requested tokens list
* @return uint256 token ID at the given index of the tokens list owned by the requested address
*/
function tokenOfOwnerByIndex(
address _owner,
uint256 _index
)
public
view
returns (uint256)
{
require(_index < balanceOf(_owner));
return ownedTokens[_owner][_index];
}
/**
* @dev Gets the total amount of tokens stored by the contract
* @return uint256 representing the total amount of tokens
*/
function totalSupply() public view returns (uint256) {
return allTokens.length;
}
/**
* @dev Gets the token ID at a given index of all the tokens in this contract
* Reverts if the index is greater or equal to the total number of tokens
* @param _index uint256 representing the index to be accessed of the tokens list
* @return uint256 token ID at the given index of the tokens list
*/
function tokenByIndex(uint256 _index) public view returns (uint256) {
require(_index < totalSupply());
return allTokens[_index];
}
/**
* @dev Internal function to set the token URI for a given token
* Reverts if the token ID does not exist
* @param _tokenId uint256 ID of the token to set its URI
* @param _uri string URI to assign
*/
function _setTokenURI(uint256 _tokenId, string _uri) internal {
require(exists(_tokenId));
tokenURIs[_tokenId] = _uri;
}
/**
* @dev Internal function to add a token ID to the list of a given address
* @param _to address representing the new owner of the given token ID
* @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function addTokenTo(address _to, uint256 _tokenId) internal {
super.addTokenTo(_to, _tokenId);
uint256 length = ownedTokens[_to].length;
ownedTokens[_to].push(_tokenId);
ownedTokensIndex[_tokenId] = length;
}
/**
* @dev Internal function to remove a token ID from the list of a given address
* @param _from address representing the previous owner of the given token ID
* @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function removeTokenFrom(address _from, uint256 _tokenId) internal {
super.removeTokenFrom(_from, _tokenId);
// To prevent a gap in the array, we store the last token in the index of the token to delete, and
// then delete the last slot.
uint256 tokenIndex = ownedTokensIndex[_tokenId];
uint256 lastTokenIndex = ownedTokens[_from].length.sub(1);
uint256 lastToken = ownedTokens[_from][lastTokenIndex];
ownedTokens[_from][tokenIndex] = lastToken;
// This also deletes the contents at the last position of the array
ownedTokens[_from].length--;
// Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
// be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping
// the lastToken to the first position, and then dropping the element placed in the last position of the list
ownedTokensIndex[_tokenId] = 0;
ownedTokensIndex[lastToken] = tokenIndex;
}
/**
* @dev Internal function to mint a new token
* Reverts if the given token ID already exists
* @param _to address the beneficiary that will own the minted token
* @param _tokenId uint256 ID of the token to be minted by the msg.sender
*/
function _mint(address _to, uint256 _tokenId) internal {
super._mint(_to, _tokenId);
allTokensIndex[_tokenId] = allTokens.length;
allTokens.push(_tokenId);
}
/**
* @dev Internal function to burn a specific token
* Reverts if the token does not exist
* @param _owner owner of the token to burn
* @param _tokenId uint256 ID of the token being burned by the msg.sender
*/
function _burn(address _owner, uint256 _tokenId) internal {
super._burn(_owner, _tokenId);
// Clear metadata (if any)
if (bytes(tokenURIs[_tokenId]).length != 0) {
delete tokenURIs[_tokenId];
}
// Reorg all tokens array
uint256 tokenIndex = allTokensIndex[_tokenId];
uint256 lastTokenIndex = allTokens.length.sub(1);
uint256 lastToken = allTokens[lastTokenIndex];
allTokens[tokenIndex] = lastToken;
allTokens[lastTokenIndex] = 0;
allTokens.length--;
allTokensIndex[_tokenId] = 0;
allTokensIndex[lastToken] = tokenIndex;
}
}
// File: @evolutionland/common/contracts/interfaces/IAuthority.sol
pragma solidity ^0.4.24;
contract IAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
// File: @evolutionland/common/contracts/DSAuth.sol
pragma solidity ^0.4.24;
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
/**
* @title DSAuth
* @dev The DSAuth contract is reference implement of https://github.com/dapphub/ds-auth
* But in the isAuthorized method, the src from address(this) is remove for safty concern.
*/
contract DSAuth is DSAuthEvents {
IAuthority public authority;
address public owner;
constructor() public {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
emit LogSetOwner(owner);
}
function setAuthority(IAuthority authority_)
public
auth
{
authority = authority_;
emit LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == owner) {
return true;
} else if (authority == IAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
// File: @evolutionland/common/contracts/StringUtil.sol
// https://github.com/Arachnid/solidity-stringutils/tree/master/src
// https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol#L1036
pragma solidity ^0.4.14;
library StringUtil {
struct slice {
uint _len;
uint _ptr;
}
function memcpy(uint dest, uint src, uint len) private pure {
// Copy word-length chunks while possible
for(; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
uint mask = 256 ** (32 - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
/*
* @dev Returns a slice containing the entire string.
* @param self The string to make a slice from.
* @return A newly allocated slice containing the entire string.
*/
function toSlice(string memory self) internal pure returns (slice memory) {
uint ptr;
assembly {
ptr := add(self, 0x20)
}
return slice(bytes(self).length, ptr);
}
/*
* @dev Returns the length of a null-terminated bytes32 string.
* @param self The value to find the length of.
* @return The length of the string, from 0 to 32.
*/
function len(bytes32 self) internal pure returns (uint) {
uint ret;
if (self == 0)
return 0;
if (self & 0xffffffffffffffffffffffffffffffff == 0) {
ret += 16;
self = bytes32(uint(self) / 0x100000000000000000000000000000000);
}
if (self & 0xffffffffffffffff == 0) {
ret += 8;
self = bytes32(uint(self) / 0x10000000000000000);
}
if (self & 0xffffffff == 0) {
ret += 4;
self = bytes32(uint(self) / 0x100000000);
}
if (self & 0xffff == 0) {
ret += 2;
self = bytes32(uint(self) / 0x10000);
}
if (self & 0xff == 0) {
ret += 1;
}
return 32 - ret;
}
/*
* @dev Returns a slice containing the entire bytes32, interpreted as a
* null-terminated utf-8 string.
* @param self The bytes32 value to convert to a slice.
* @return A new slice containing the value of the input argument up to the
* first null.
*/
function toSliceB32(bytes32 self) internal pure returns (slice memory ret) {
// Allocate space for `self` in memory, copy it there, and point ret at it
assembly {
let ptr := mload(0x40)
mstore(0x40, add(ptr, 0x20))
mstore(ptr, self)
mstore(add(ret, 0x20), ptr)
}
ret._len = len(self);
}
/*
* @dev Returns a new slice containing the same data as the current slice.
* @param self The slice to copy.
* @return A new slice containing the same data as `self`.
*/
function copy(slice memory self) internal pure returns (slice memory) {
return slice(self._len, self._ptr);
}
/*
* @dev Copies a slice to a new string.
* @param self The slice to copy.
* @return A newly allocated string containing the slice's text.
*/
function toString(slice memory self) internal pure returns (string memory) {
string memory ret = new string(self._len);
uint retptr;
assembly { retptr := add(ret, 32) }
memcpy(retptr, self._ptr, self._len);
return ret;
}
/*
* @dev Returns the length in runes of the slice. Note that this operation
* takes time proportional to the length of the slice; avoid using it
* in loops, and call `slice.empty()` if you only need to know whether
* the slice is empty or not.
* @param self The slice to operate on.
* @return The length of the slice in runes.
*/
function len(slice memory self) internal pure returns (uint l) {
// Starting at ptr-31 means the LSB will be the byte we care about
uint ptr = self._ptr - 31;
uint end = ptr + self._len;
for (l = 0; ptr < end; l++) {
uint8 b;
assembly { b := and(mload(ptr), 0xFF) }
if (b < 0x80) {
ptr += 1;
} else if(b < 0xE0) {
ptr += 2;
} else if(b < 0xF0) {
ptr += 3;
} else if(b < 0xF8) {
ptr += 4;
} else if(b < 0xFC) {
ptr += 5;
} else {
ptr += 6;
}
}
}
/*
* @dev Returns true if the slice is empty (has a length of 0).
* @param self The slice to operate on.
* @return True if the slice is empty, False otherwise.
*/
function empty(slice memory self) internal pure returns (bool) {
return self._len == 0;
}
/*
* @dev Returns a positive number if `other` comes lexicographically after
* `self`, a negative number if it comes before, or zero if the
* contents of the two slices are equal. Comparison is done per-rune,
* on unicode codepoints.
* @param self The first slice to compare.
* @param other The second slice to compare.
* @return The result of the comparison.
*/
function compare(slice memory self, slice memory other) internal pure returns (int) {
uint shortest = self._len;
if (other._len < self._len)
shortest = other._len;
uint selfptr = self._ptr;
uint otherptr = other._ptr;
for (uint idx = 0; idx < shortest; idx += 32) {
uint a;
uint b;
assembly {
a := mload(selfptr)
b := mload(otherptr)
}
if (a != b) {
// Mask out irrelevant bytes and check again
uint256 mask = uint256(-1); // 0xffff...
if(shortest < 32) {
mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);
}
uint256 diff = (a & mask) - (b & mask);
if (diff != 0)
return int(diff);
}
selfptr += 32;
otherptr += 32;
}
return int(self._len) - int(other._len);
}
/*
* @dev Returns true if the two slices contain the same text.
* @param self The first slice to compare.
* @param self The second slice to compare.
* @return True if the slices are equal, false otherwise.
*/
function equals(slice memory self, slice memory other) internal pure returns (bool) {
return compare(self, other) == 0;
}
/*
* @dev Extracts the first rune in the slice into `rune`, advancing the
* slice to point to the next rune and returning `self`.
* @param self The slice to operate on.
* @param rune The slice that will contain the first rune.
* @return `rune`.
*/
function nextRune(slice memory self, slice memory rune) internal pure returns (slice memory) {
rune._ptr = self._ptr;
if (self._len == 0) {
rune._len = 0;
return rune;
}
uint l;
uint b;
// Load the first byte of the rune into the LSBs of b
assembly { b := and(mload(sub(mload(add(self, 32)), 31)), 0xFF) }
if (b < 0x80) {
l = 1;
} else if(b < 0xE0) {
l = 2;
} else if(b < 0xF0) {
l = 3;
} else {
l = 4;
}
// Check for truncated codepoints
if (l > self._len) {
rune._len = self._len;
self._ptr += self._len;
self._len = 0;
return rune;
}
self._ptr += l;
self._len -= l;
rune._len = l;
return rune;
}
/*
* @dev Returns the first rune in the slice, advancing the slice to point
* to the next rune.
* @param self The slice to operate on.
* @return A slice containing only the first rune from `self`.
*/
function nextRune(slice memory self) internal pure returns (slice memory ret) {
nextRune(self, ret);
}
/*
* @dev Returns the number of the first codepoint in the slice.
* @param self The slice to operate on.
* @return The number of the first codepoint in the slice.
*/
function ord(slice memory self) internal pure returns (uint ret) {
if (self._len == 0) {
return 0;
}
uint word;
uint length;
uint divisor = 2 ** 248;
// Load the rune into the MSBs of b
assembly { word:= mload(mload(add(self, 32))) }
uint b = word / divisor;
if (b < 0x80) {
ret = b;
length = 1;
} else if(b < 0xE0) {
ret = b & 0x1F;
length = 2;
} else if(b < 0xF0) {
ret = b & 0x0F;
length = 3;
} else {
ret = b & 0x07;
length = 4;
}
// Check for truncated codepoints
if (length > self._len) {
return 0;
}
for (uint i = 1; i < length; i++) {
divisor = divisor / 256;
b = (word / divisor) & 0xFF;
if (b & 0xC0 != 0x80) {
// Invalid UTF-8 sequence
return 0;
}
ret = (ret * 64) | (b & 0x3F);
}
return ret;
}
/*
* @dev Returns the keccak-256 hash of the slice.
* @param self The slice to hash.
* @return The hash of the slice.
*/
function keccak(slice memory self) internal pure returns (bytes32 ret) {
assembly {
ret := keccak256(mload(add(self, 32)), mload(self))
}
}
/*
* @dev Returns true if `self` starts with `needle`.
* @param self The slice to operate on.
* @param needle The slice to search for.
* @return True if the slice starts with the provided text, false otherwise.
*/
function startsWith(slice memory self, slice memory needle) internal pure returns (bool) {
if (self._len < needle._len) {
return false;
}
if (self._ptr == needle._ptr) {
return true;
}
bool equal;
assembly {
let length := mload(needle)
let selfptr := mload(add(self, 0x20))
let needleptr := mload(add(needle, 0x20))
equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
}
return equal;
}
/*
* @dev If `self` starts with `needle`, `needle` is removed from the
* beginning of `self`. Otherwise, `self` is unmodified.
* @param self The slice to operate on.
* @param needle The slice to search for.
* @return `self`
*/
function beyond(slice memory self, slice memory needle) internal pure returns (slice memory) {
if (self._len < needle._len) {
return self;
}
bool equal = true;
if (self._ptr != needle._ptr) {
assembly {
let length := mload(needle)
let selfptr := mload(add(self, 0x20))
let needleptr := mload(add(needle, 0x20))
equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
}
}
if (equal) {
self._len -= needle._len;
self._ptr += needle._len;
}
return self;
}
/*
* @dev Returns true if the slice ends with `needle`.
* @param self The slice to operate on.
* @param needle The slice to search for.
* @return True if the slice starts with the provided text, false otherwise.
*/
function endsWith(slice memory self, slice memory needle) internal pure returns (bool) {
if (self._len < needle._len) {
return false;
}
uint selfptr = self._ptr + self._len - needle._len;
if (selfptr == needle._ptr) {
return true;
}
bool equal;
assembly {
let length := mload(needle)
let needleptr := mload(add(needle, 0x20))
equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
}
return equal;
}
/*
* @dev If `self` ends with `needle`, `needle` is removed from the
* end of `self`. Otherwise, `self` is unmodified.
* @param self The slice to operate on.
* @param needle The slice to search for.
* @return `self`
*/
function until(slice memory self, slice memory needle) internal pure returns (slice memory) {
if (self._len < needle._len) {
return self;
}
uint selfptr = self._ptr + self._len - needle._len;
bool equal = true;
if (selfptr != needle._ptr) {
assembly {
let length := mload(needle)
let needleptr := mload(add(needle, 0x20))
equal := eq(keccak256(selfptr, length), keccak256(needleptr, length))
}
}
if (equal) {
self._len -= needle._len;
}
return self;
}
// Returns the memory address of the first byte of the first occurrence of
// `needle` in `self`, or the first byte after `self` if not found.
function findPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private pure returns (uint) {
uint ptr = selfptr;
uint idx;
if (needlelen <= selflen) {
if (needlelen <= 32) {
bytes32 mask = bytes32(~(2 ** (8 * (32 - needlelen)) - 1));
bytes32 needledata;
assembly { needledata := and(mload(needleptr), mask) }
uint end = selfptr + selflen - needlelen;
bytes32 ptrdata;
assembly { ptrdata := and(mload(ptr), mask) }
while (ptrdata != needledata) {
if (ptr >= end)
return selfptr + selflen;
ptr++;
assembly { ptrdata := and(mload(ptr), mask) }
}
return ptr;
} else {
// For long needles, use hashing
bytes32 hash;
assembly { hash := keccak256(needleptr, needlelen) }
for (idx = 0; idx <= selflen - needlelen; idx++) {
bytes32 testHash;
assembly { testHash := keccak256(ptr, needlelen) }
if (hash == testHash)
return ptr;
ptr += 1;
}
}
}
return selfptr + selflen;
}
// Returns the memory address of the first byte after the last occurrence of
// `needle` in `self`, or the address of `self` if not found.
function rfindPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private pure returns (uint) {
uint ptr;
if (needlelen <= selflen) {
if (needlelen <= 32) {
bytes32 mask = bytes32(~(2 ** (8 * (32 - needlelen)) - 1));
bytes32 needledata;
assembly { needledata := and(mload(needleptr), mask) }
ptr = selfptr + selflen - needlelen;
bytes32 ptrdata;
assembly { ptrdata := and(mload(ptr), mask) }
while (ptrdata != needledata) {
if (ptr <= selfptr)
return selfptr;
ptr--;
assembly { ptrdata := and(mload(ptr), mask) }
}
return ptr + needlelen;
} else {
// For long needles, use hashing
bytes32 hash;
assembly { hash := keccak256(needleptr, needlelen) }
ptr = selfptr + (selflen - needlelen);
while (ptr >= selfptr) {
bytes32 testHash;
assembly { testHash := keccak256(ptr, needlelen) }
if (hash == testHash)
return ptr + needlelen;
ptr -= 1;
}
}
}
return selfptr;
}
/*
* @dev Modifies `self` to contain everything from the first occurrence of
* `needle` to the end of the slice. `self` is set to the empty slice
* if `needle` is not found.
* @param self The slice to search and modify.
* @param needle The text to search for.
* @return `self`.
*/
function find(slice memory self, slice memory needle) internal pure returns (slice memory) {
uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
self._len -= ptr - self._ptr;
self._ptr = ptr;
return self;
}
/*
* @dev Modifies `self` to contain the part of the string from the start of
* `self` to the end of the first occurrence of `needle`. If `needle`
* is not found, `self` is set to the empty slice.
* @param self The slice to search and modify.
* @param needle The text to search for.
* @return `self`.
*/
function rfind(slice memory self, slice memory needle) internal pure returns (slice memory) {
uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr);
self._len = ptr - self._ptr;
return self;
}
/*
* @dev Splits the slice, setting `self` to everything after the first
* occurrence of `needle`, and `token` to everything before it. If
* `needle` does not occur in `self`, `self` is set to the empty slice,
* and `token` is set to the entirety of `self`.
* @param self The slice to split.
* @param needle The text to search for in `self`.
* @param token An output parameter to which the first token is written.
* @return `token`.
*/
function split(slice memory self, slice memory needle, slice memory token) internal pure returns (slice memory) {
uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
token._ptr = self._ptr;
token._len = ptr - self._ptr;
if (ptr == self._ptr + self._len) {
// Not found
self._len = 0;
} else {
self._len -= token._len + needle._len;
self._ptr = ptr + needle._len;
}
return token;
}
/*
* @dev Splits the slice, setting `self` to everything after the first
* occurrence of `needle`, and returning everything before it. If
* `needle` does not occur in `self`, `self` is set to the empty slice,
* and the entirety of `self` is returned.
* @param self The slice to split.
* @param needle The text to search for in `self`.
* @return The part of `self` up to the first occurrence of `delim`.
*/
function split(slice memory self, slice memory needle) internal pure returns (slice memory token) {
split(self, needle, token);
}
/*
* @dev Splits the slice, setting `self` to everything before the last
* occurrence of `needle`, and `token` to everything after it. If
* `needle` does not occur in `self`, `self` is set to the empty slice,
* and `token` is set to the entirety of `self`.
* @param self The slice to split.
* @param needle The text to search for in `self`.
* @param token An output parameter to which the first token is written.
* @return `token`.
*/
function rsplit(slice memory self, slice memory needle, slice memory token) internal pure returns (slice memory) {
uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr);
token._ptr = ptr;
token._len = self._len - (ptr - self._ptr);
if (ptr == self._ptr) {
// Not found
self._len = 0;
} else {
self._len -= token._len + needle._len;
}
return token;
}
/*
* @dev Splits the slice, setting `self` to everything before the last
* occurrence of `needle`, and returning everything after it. If
* `needle` does not occur in `self`, `self` is set to the empty slice,
* and the entirety of `self` is returned.
* @param self The slice to split.
* @param needle The text to search for in `self`.
* @return The part of `self` after the last occurrence of `delim`.
*/
function rsplit(slice memory self, slice memory needle) internal pure returns (slice memory token) {
rsplit(self, needle, token);
}
/*
* @dev Counts the number of nonoverlapping occurrences of `needle` in `self`.
* @param self The slice to search.
* @param needle The text to search for in `self`.
* @return The number of occurrences of `needle` found in `self`.
*/
function count(slice memory self, slice memory needle) internal pure returns (uint cnt) {
uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr) + needle._len;
while (ptr <= self._ptr + self._len) {
cnt++;
ptr = findPtr(self._len - (ptr - self._ptr), ptr, needle._len, needle._ptr) + needle._len;
}
}
/*
* @dev Returns True if `self` contains `needle`.
* @param self The slice to search.
* @param needle The text to search for in `self`.
* @return True if `needle` is found in `self`, false otherwise.
*/
function contains(slice memory self, slice memory needle) internal pure returns (bool) {
return rfindPtr(self._len, self._ptr, needle._len, needle._ptr) != self._ptr;
}
/*
* @dev Returns a newly allocated string containing the concatenation of
* `self` and `other`.
* @param self The first slice to concatenate.
* @param other The second slice to concatenate.
* @return The concatenation of the two strings.
*/
function concat(slice memory self, slice memory other) internal pure returns (string memory) {
string memory ret = new string(self._len + other._len);
uint retptr;
assembly { retptr := add(ret, 32) }
memcpy(retptr, self._ptr, self._len);
memcpy(retptr + self._len, other._ptr, other._len);
return ret;
}
/*
* @dev Joins an array of slices, using `self` as a delimiter, returning a
* newly allocated string.
* @param self The delimiter to use.
* @param parts A list of slices to join.
* @return A newly allocated string containing all the slices in `parts`,
* joined with `self`.
*/
function join(slice memory self, slice[] memory parts) internal pure returns (string memory) {
if (parts.length == 0)
return "";
uint length = self._len * (parts.length - 1);
for(uint i = 0; i < parts.length; i++)
length += parts[i]._len;
string memory ret = new string(length);
uint retptr;
assembly { retptr := add(ret, 32) }
for(i = 0; i < parts.length; i++) {
memcpy(retptr, parts[i]._ptr, parts[i]._len);
retptr += parts[i]._len;
if (i < parts.length - 1) {
memcpy(retptr, self._ptr, self._len);
retptr += self._len;
}
}
return ret;
}
function uint2str(uint _int) internal pure returns (string memory _uintAsString) {
uint _i = _int;
if (_i == 0) {
return "0";
}
uint j = _i;
uint length;
while (j != 0) {
length++;
j /= 10;
}
bytes memory bstr = new bytes(length);
uint k = length - 1;
while (_i != 0) {
bstr[k--] = byte(uint8(48 + _i % 10));
_i /= 10;
}
return string(bstr);
}
}
// File: contracts/IteringNFT.sol
pragma solidity ^0.4.24;
contract IteringNFT is ERC721Token("Itering Objects","ITO"), DSAuth {
using StringUtil for *;
// https://docs.opensea.io/docs/2-adding-metadata
string public baseTokenURI;
function tokenURI(uint256 _tokenId) public view returns (string) {
if (super.tokenURI(_tokenId).toSlice().empty()) {
return baseTokenURI.toSlice().concat(StringUtil.uint2str(_tokenId).toSlice());
}
return super.tokenURI(_tokenId);
}
function setTokenURI(uint256 _tokenId, string _uri) public auth {
_setTokenURI(_tokenId, _uri);
}
function setBaseTokenURI(string _newBaseTokenURI) public auth {
baseTokenURI = _newBaseTokenURI;
}
function mint(address _to, uint256 _tokenId) public auth {
super._mint(_to, _tokenId);
}
function burn(address _to, uint256 _tokenId) public auth {
super._burn(_to, _tokenId);
}
//@dev user invoke approveAndCall to create auction
//@param _to - address of auction contractß
function approveAndCall(
address _to,
uint _tokenId,
bytes _extraData
) public {
// set _to to the auction contract
approve(_to, _tokenId);
if(!_to.call(
bytes4(keccak256("receiveApproval(address,uint256,bytes)")), abi.encode(msg.sender, _tokenId, _extraData)
)) {
revert();
}
}
}
// File: openzeppelin-solidity/contracts/ownership/Ownable.sol
pragma solidity ^0.4.24;
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to relinquish control of the contract.
* @notice Renouncing to ownership will leave the contract without an owner.
* It will not be possible to call the functions with the `onlyOwner`
* modifier anymore.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipRenounced(owner);
owner = address(0);
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function transferOwnership(address _newOwner) public onlyOwner {
_transferOwnership(_newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function _transferOwnership(address _newOwner) internal {
require(_newOwner != address(0));
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}
// File: openzeppelin-solidity/contracts/introspection/ERC165.sol
pragma solidity ^0.4.24;
/**
* @title ERC165
* @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
*/
interface ERC165 {
/**
* @notice Query if a contract implements an interface
* @param _interfaceId The interface identifier, as specified in ERC-165
* @dev Interface identification is specified in ERC-165. This function
* uses less than 30,000 gas.
*/
function supportsInterface(bytes4 _interfaceId)
external
view
returns (bool);
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721Basic.sol
pragma solidity ^0.4.24;
/**
* @title ERC721 Non-Fungible Token Standard basic interface
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Basic is ERC165 {
bytes4 internal constant InterfaceId_ERC721 = 0x80ac58cd;
/*
* 0x80ac58cd ===
* bytes4(keccak256('balanceOf(address)')) ^
* bytes4(keccak256('ownerOf(uint256)')) ^
* bytes4(keccak256('approve(address,uint256)')) ^
* bytes4(keccak256('getApproved(uint256)')) ^
* bytes4(keccak256('setApprovalForAll(address,bool)')) ^
* bytes4(keccak256('isApprovedForAll(address,address)')) ^
* bytes4(keccak256('transferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
*/
bytes4 internal constant InterfaceId_ERC721Exists = 0x4f558e79;
/*
* 0x4f558e79 ===
* bytes4(keccak256('exists(uint256)'))
*/
bytes4 internal constant InterfaceId_ERC721Enumerable = 0x780e9d63;
/**
* 0x780e9d63 ===
* bytes4(keccak256('totalSupply()')) ^
* bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^
* bytes4(keccak256('tokenByIndex(uint256)'))
*/
bytes4 internal constant InterfaceId_ERC721Metadata = 0x5b5e139f;
/**
* 0x5b5e139f ===
* bytes4(keccak256('name()')) ^
* bytes4(keccak256('symbol()')) ^
* bytes4(keccak256('tokenURI(uint256)'))
*/
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) public view returns (uint256 _balance);
function ownerOf(uint256 _tokenId) public view returns (address _owner);
function exists(uint256 _tokenId) public view returns (bool _exists);
function approve(address _to, uint256 _tokenId) public;
function getApproved(uint256 _tokenId)
public view returns (address _operator);
function setApprovalForAll(address _operator, bool _approved) public;
function isApprovedForAll(address _owner, address _operator)
public view returns (bool);
function transferFrom(address _from, address _to, uint256 _tokenId) public;
function safeTransferFrom(address _from, address _to, uint256 _tokenId)
public;
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes _data
)
public;
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721.sol
pragma solidity ^0.4.24;
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Enumerable is ERC721Basic {
function totalSupply() public view returns (uint256);
function tokenOfOwnerByIndex(
address _owner,
uint256 _index
)
public
view
returns (uint256 _tokenId);
function tokenByIndex(uint256 _index) public view returns (uint256);
}
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Metadata is ERC721Basic {
function name() external view returns (string _name);
function symbol() external view returns (string _symbol);
function tokenURI(uint256 _tokenId) public view returns (string);
}
/**
* @title ERC-721 Non-Fungible Token Standard, full implementation interface
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata {
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721Receiver.sol
pragma solidity ^0.4.24;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
contract ERC721Receiver {
/**
* @dev Magic value to be returned upon successful reception of an NFT
* Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`,
* which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
*/
bytes4 internal constant ERC721_RECEIVED = 0x150b7a02;
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a `safetransfer`. This function MAY throw to revert and reject the
* transfer. Return of other than the magic value MUST result in the
* transaction being reverted.
* Note: the contract address is always the message sender.
* @param _operator The address which called `safeTransferFrom` function
* @param _from The address which previously owned the token
* @param _tokenId The NFT identifier which is being transferred
* @param _data Additional data with no specified format
* @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
*/
function onERC721Received(
address _operator,
address _from,
uint256 _tokenId,
bytes _data
)
public
returns(bytes4);
}
// File: openzeppelin-solidity/contracts/math/SafeMath.sol
pragma solidity ^0.4.24;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
// Gas optimization: this is cheaper than asserting 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (_a == 0) {
return 0;
}
c = _a * _b;
assert(c / _a == _b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
// assert(_b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = _a / _b;
// assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
return _a / _b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
assert(_b <= _a);
return _a - _b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
c = _a + _b;
assert(c >= _a);
return c;
}
}
// File: openzeppelin-solidity/contracts/AddressUtils.sol
pragma solidity ^0.4.24;
/**
* Utility library of inline functions on addresses
*/
library AddressUtils {
/**
* Returns whether the target address is a contract
* @dev This function will return false if invoked during the constructor of a contract,
* as the code is not actually created until after the constructor finishes.
* @param _addr address to check
* @return whether the target address is a contract
*/
function isContract(address _addr) internal view returns (bool) {
uint256 size;
// XXX Currently there is no better way to check if there is a contract in an address
// than to check the size of the code at that address.
// See https://ethereum.stackexchange.com/a/14016/36603
// for more details about how this works.
// TODO Check this again before the Serenity release, because all addresses will be
// contracts then.
// solium-disable-next-line security/no-inline-assembly
assembly { size := extcodesize(_addr) }
return size > 0;
}
}
// File: openzeppelin-solidity/contracts/introspection/SupportsInterfaceWithLookup.sol
pragma solidity ^0.4.24;
/**
* @title SupportsInterfaceWithLookup
* @author Matt Condon (@shrugs)
* @dev Implements ERC165 using a lookup table.
*/
contract SupportsInterfaceWithLookup is ERC165 {
bytes4 public constant InterfaceId_ERC165 = 0x01ffc9a7;
/**
* 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)'))
*/
/**
* @dev a mapping of interface id to whether or not it's supported
*/
mapping(bytes4 => bool) internal supportedInterfaces;
/**
* @dev A contract implementing SupportsInterfaceWithLookup
* implement ERC165 itself
*/
constructor()
public
{
_registerInterface(InterfaceId_ERC165);
}
/**
* @dev implement supportsInterface(bytes4) using a lookup table
*/
function supportsInterface(bytes4 _interfaceId)
external
view
returns (bool)
{
return supportedInterfaces[_interfaceId];
}
/**
* @dev private method for registering an interface
*/
function _registerInterface(bytes4 _interfaceId)
internal
{
require(_interfaceId != 0xffffffff);
supportedInterfaces[_interfaceId] = true;
}
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721BasicToken.sol
pragma solidity ^0.4.24;
/**
* @title ERC721 Non-Fungible Token Standard basic implementation
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic {
using SafeMath for uint256;
using AddressUtils for address;
// Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
// which can be also obtained as `ERC721Receiver(0).onERC721Received.selector`
bytes4 private constant ERC721_RECEIVED = 0x150b7a02;
// Mapping from token ID to owner
mapping (uint256 => address) internal tokenOwner;
// Mapping from token ID to approved address
mapping (uint256 => address) internal tokenApprovals;
// Mapping from owner to number of owned token
mapping (address => uint256) internal ownedTokensCount;
// Mapping from owner to operator approvals
mapping (address => mapping (address => bool)) internal operatorApprovals;
constructor()
public
{
// register the supported interfaces to conform to ERC721 via ERC165
_registerInterface(InterfaceId_ERC721);
_registerInterface(InterfaceId_ERC721Exists);
}
/**
* @dev Gets the balance of the specified address
* @param _owner address to query the balance of
* @return uint256 representing the amount owned by the passed address
*/
function balanceOf(address _owner) public view returns (uint256) {
require(_owner != address(0));
return ownedTokensCount[_owner];
}
/**
* @dev Gets the owner of the specified token ID
* @param _tokenId uint256 ID of the token to query the owner of
* @return owner address currently marked as the owner of the given token ID
*/
function ownerOf(uint256 _tokenId) public view returns (address) {
address owner = tokenOwner[_tokenId];
require(owner != address(0));
return owner;
}
/**
* @dev Returns whether the specified token exists
* @param _tokenId uint256 ID of the token to query the existence of
* @return whether the token exists
*/
function exists(uint256 _tokenId) public view returns (bool) {
address owner = tokenOwner[_tokenId];
return owner != address(0);
}
/**
* @dev Approves another address to transfer the given token ID
* The zero address indicates there is no approved address.
* There can only be one approved address per token at a given time.
* Can only be called by the token owner or an approved operator.
* @param _to address to be approved for the given token ID
* @param _tokenId uint256 ID of the token to be approved
*/
function approve(address _to, uint256 _tokenId) public {
address owner = ownerOf(_tokenId);
require(_to != owner);
require(msg.sender == owner || isApprovedForAll(owner, msg.sender));
tokenApprovals[_tokenId] = _to;
emit Approval(owner, _to, _tokenId);
}
/**
* @dev Gets the approved address for a token ID, or zero if no address set
* @param _tokenId uint256 ID of the token to query the approval of
* @return address currently approved for the given token ID
*/
function getApproved(uint256 _tokenId) public view returns (address) {
return tokenApprovals[_tokenId];
}
/**
* @dev Sets or unsets the approval of a given operator
* An operator is allowed to transfer all tokens of the sender on their behalf
* @param _to operator address to set the approval
* @param _approved representing the status of the approval to be set
*/
function setApprovalForAll(address _to, bool _approved) public {
require(_to != msg.sender);
operatorApprovals[msg.sender][_to] = _approved;
emit ApprovalForAll(msg.sender, _to, _approved);
}
/**
* @dev Tells whether an operator is approved by a given owner
* @param _owner owner address which you want to query the approval of
* @param _operator operator address which you want to query the approval of
* @return bool whether the given operator is approved by the given owner
*/
function isApprovedForAll(
address _owner,
address _operator
)
public
view
returns (bool)
{
return operatorApprovals[_owner][_operator];
}
/**
* @dev Transfers the ownership of a given token ID to another address
* Usage of this method is discouraged, use `safeTransferFrom` whenever possible
* Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
*/
function transferFrom(
address _from,
address _to,
uint256 _tokenId
)
public
{
require(isApprovedOrOwner(msg.sender, _tokenId));
require(_from != address(0));
require(_to != address(0));
clearApproval(_from, _tokenId);
removeTokenFrom(_from, _tokenId);
addTokenTo(_to, _tokenId);
emit Transfer(_from, _to, _tokenId);
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
*
* Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
*/
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
)
public
{
// solium-disable-next-line arg-overflow
safeTransferFrom(_from, _to, _tokenId, "");
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
* Requires the msg sender to be the owner, approved, or operator
* @param _from current owner of the token
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
* @param _data bytes data to send along with a safe transfer check
*/
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes _data
)
public
{
transferFrom(_from, _to, _tokenId);
// solium-disable-next-line arg-overflow
require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data));
}
/**
* @dev Returns whether the given spender can transfer a given token ID
* @param _spender address of the spender to query
* @param _tokenId uint256 ID of the token to be transferred
* @return bool whether the msg.sender is approved for the given token ID,
* is an operator of the owner, or is the owner of the token
*/
function isApprovedOrOwner(
address _spender,
uint256 _tokenId
)
internal
view
returns (bool)
{
address owner = ownerOf(_tokenId);
// Disable solium check because of
// https://github.com/duaraghav8/Solium/issues/175
// solium-disable-next-line operator-whitespace
return (
_spender == owner ||
getApproved(_tokenId) == _spender ||
isApprovedForAll(owner, _spender)
);
}
/**
* @dev Internal function to mint a new token
* Reverts if the given token ID already exists
* @param _to The address that will own the minted token
* @param _tokenId uint256 ID of the token to be minted by the msg.sender
*/
function _mint(address _to, uint256 _tokenId) internal {
require(_to != address(0));
addTokenTo(_to, _tokenId);
emit Transfer(address(0), _to, _tokenId);
}
/**
* @dev Internal function to burn a specific token
* Reverts if the token does not exist
* @param _tokenId uint256 ID of the token being burned by the msg.sender
*/
function _burn(address _owner, uint256 _tokenId) internal {
clearApproval(_owner, _tokenId);
removeTokenFrom(_owner, _tokenId);
emit Transfer(_owner, address(0), _tokenId);
}
/**
* @dev Internal function to clear current approval of a given token ID
* Reverts if the given address is not indeed the owner of the token
* @param _owner owner of the token
* @param _tokenId uint256 ID of the token to be transferred
*/
function clearApproval(address _owner, uint256 _tokenId) internal {
require(ownerOf(_tokenId) == _owner);
if (tokenApprovals[_tokenId] != address(0)) {
tokenApprovals[_tokenId] = address(0);
}
}
/**
* @dev Internal function to add a token ID to the list of a given address
* @param _to address representing the new owner of the given token ID
* @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function addTokenTo(address _to, uint256 _tokenId) internal {
require(tokenOwner[_tokenId] == address(0));
tokenOwner[_tokenId] = _to;
ownedTokensCount[_to] = ownedTokensCount[_to].add(1);
}
/**
* @dev Internal function to remove a token ID from the list of a given address
* @param _from address representing the previous owner of the given token ID
* @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function removeTokenFrom(address _from, uint256 _tokenId) internal {
require(ownerOf(_tokenId) == _from);
ownedTokensCount[_from] = ownedTokensCount[_from].sub(1);
tokenOwner[_tokenId] = address(0);
}
/**
* @dev Internal function to invoke `onERC721Received` on a target address
* The call is not executed if the target address is not a contract
* @param _from address representing the previous owner of the given token ID
* @param _to target address that will receive the tokens
* @param _tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return whether the call correctly returned the expected magic value
*/
function checkAndCallSafeTransfer(
address _from,
address _to,
uint256 _tokenId,
bytes _data
)
internal
returns (bool)
{
if (!_to.isContract()) {
return true;
}
bytes4 retval = ERC721Receiver(_to).onERC721Received(
msg.sender, _from, _tokenId, _data);
return (retval == ERC721_RECEIVED);
}
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721Token.sol
pragma solidity ^0.4.24;
/**
* @title Full ERC721 Token
* This implementation includes all the required and some optional functionality of the ERC721 standard
* Moreover, it includes approve all functionality using operator terminology
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Token is SupportsInterfaceWithLookup, ERC721BasicToken, ERC721 {
// Token name
string internal name_;
// Token symbol
string internal symbol_;
// Mapping from owner to list of owned token IDs
mapping(address => uint256[]) internal ownedTokens;
// Mapping from token ID to index of the owner tokens list
mapping(uint256 => uint256) internal ownedTokensIndex;
// Array with all token ids, used for enumeration
uint256[] internal allTokens;
// Mapping from token id to position in the allTokens array
mapping(uint256 => uint256) internal allTokensIndex;
// Optional mapping for token URIs
mapping(uint256 => string) internal tokenURIs;
/**
* @dev Constructor function
*/
constructor(string _name, string _symbol) public {
name_ = _name;
symbol_ = _symbol;
// register the supported interfaces to conform to ERC721 via ERC165
_registerInterface(InterfaceId_ERC721Enumerable);
_registerInterface(InterfaceId_ERC721Metadata);
}
/**
* @dev Gets the token name
* @return string representing the token name
*/
function name() external view returns (string) {
return name_;
}
/**
* @dev Gets the token symbol
* @return string representing the token symbol
*/
function symbol() external view returns (string) {
return symbol_;
}
/**
* @dev Returns an URI for a given token ID
* Throws if the token ID does not exist. May return an empty string.
* @param _tokenId uint256 ID of the token to query
*/
function tokenURI(uint256 _tokenId) public view returns (string) {
require(exists(_tokenId));
return tokenURIs[_tokenId];
}
/**
* @dev Gets the token ID at a given index of the tokens list of the requested owner
* @param _owner address owning the tokens list to be accessed
* @param _index uint256 representing the index to be accessed of the requested tokens list
* @return uint256 token ID at the given index of the tokens list owned by the requested address
*/
function tokenOfOwnerByIndex(
address _owner,
uint256 _index
)
public
view
returns (uint256)
{
require(_index < balanceOf(_owner));
return ownedTokens[_owner][_index];
}
/**
* @dev Gets the total amount of tokens stored by the contract
* @return uint256 representing the total amount of tokens
*/
function totalSupply() public view returns (uint256) {
return allTokens.length;
}
/**
* @dev Gets the token ID at a given index of all the tokens in this contract
* Reverts if the index is greater or equal to the total number of tokens
* @param _index uint256 representing the index to be accessed of the tokens list
* @return uint256 token ID at the given index of the tokens list
*/
function tokenByIndex(uint256 _index) public view returns (uint256) {
require(_index < totalSupply());
return allTokens[_index];
}
/**
* @dev Internal function to set the token URI for a given token
* Reverts if the token ID does not exist
* @param _tokenId uint256 ID of the token to set its URI
* @param _uri string URI to assign
*/
function _setTokenURI(uint256 _tokenId, string _uri) internal {
require(exists(_tokenId));
tokenURIs[_tokenId] = _uri;
}
/**
* @dev Internal function to add a token ID to the list of a given address
* @param _to address representing the new owner of the given token ID
* @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function addTokenTo(address _to, uint256 _tokenId) internal {
super.addTokenTo(_to, _tokenId);
uint256 length = ownedTokens[_to].length;
ownedTokens[_to].push(_tokenId);
ownedTokensIndex[_tokenId] = length;
}
/**
* @dev Internal function to remove a token ID from the list of a given address
* @param _from address representing the previous owner of the given token ID
* @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function removeTokenFrom(address _from, uint256 _tokenId) internal {
super.removeTokenFrom(_from, _tokenId);
// To prevent a gap in the array, we store the last token in the index of the token to delete, and
// then delete the last slot.
uint256 tokenIndex = ownedTokensIndex[_tokenId];
uint256 lastTokenIndex = ownedTokens[_from].length.sub(1);
uint256 lastToken = ownedTokens[_from][lastTokenIndex];
ownedTokens[_from][tokenIndex] = lastToken;
// This also deletes the contents at the last position of the array
ownedTokens[_from].length--;
// Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
// be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping
// the lastToken to the first position, and then dropping the element placed in the last position of the list
ownedTokensIndex[_tokenId] = 0;
ownedTokensIndex[lastToken] = tokenIndex;
}
/**
* @dev Internal function to mint a new token
* Reverts if the given token ID already exists
* @param _to address the beneficiary that will own the minted token
* @param _tokenId uint256 ID of the token to be minted by the msg.sender
*/
function _mint(address _to, uint256 _tokenId) internal {
super._mint(_to, _tokenId);
allTokensIndex[_tokenId] = allTokens.length;
allTokens.push(_tokenId);
}
/**
* @dev Internal function to burn a specific token
* Reverts if the token does not exist
* @param _owner owner of the token to burn
* @param _tokenId uint256 ID of the token being burned by the msg.sender
*/
function _burn(address _owner, uint256 _tokenId) internal {
super._burn(_owner, _tokenId);
// Clear metadata (if any)
if (bytes(tokenURIs[_tokenId]).length != 0) {
delete tokenURIs[_tokenId];
}
// Reorg all tokens array
uint256 tokenIndex = allTokensIndex[_tokenId];
uint256 lastTokenIndex = allTokens.length.sub(1);
uint256 lastToken = allTokens[lastTokenIndex];
allTokens[tokenIndex] = lastToken;
allTokens[lastTokenIndex] = 0;
allTokens.length--;
allTokensIndex[_tokenId] = 0;
allTokensIndex[lastToken] = tokenIndex;
}
}
// File: contracts/interfaces/IInterstellarEncoder.sol
pragma solidity ^0.4.24;
contract IInterstellarEncoder {
uint256 constant CLEAR_HIGH = 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;
uint256 public constant MAGIC_NUMBER = 42; // Interstellar Encoding Magic Number.
uint256 public constant CHAIN_ID = 1; // Ethereum mainet.
uint256 public constant CURRENT_LAND = 1; // 1 is Atlantis, 0 is NaN.
enum ObjectClass {
NaN,
LAND,
APOSTLE,
OBJECT_CLASS_COUNT
}
function registerNewObjectClass(address _objectContract, uint8 objectClass) public;
function registerNewTokenContract(address _tokenAddress) public;
function encodeTokenId(address _tokenAddress, uint8 _objectClass, uint128 _objectIndex) public view returns (uint256 _tokenId);
function encodeTokenIdForObjectContract(
address _tokenAddress, address _objectContract, uint128 _objectId) public view returns (uint256 _tokenId);
function getContractAddress(uint256 _tokenId) public view returns (address);
function getObjectId(uint256 _tokenId) public view returns (uint128 _objectId);
function getObjectClass(uint256 _tokenId) public view returns (uint8);
function getObjectAddress(uint256 _tokenId) public view returns (address);
}
// File: contracts/interfaces/ISettingsRegistry.sol
pragma solidity ^0.4.24;
contract ISettingsRegistry {
enum SettingsValueTypes { NONE, UINT, STRING, ADDRESS, BYTES, BOOL, INT }
function uintOf(bytes32 _propertyName) public view returns (uint256);
function stringOf(bytes32 _propertyName) public view returns (string);
function addressOf(bytes32 _propertyName) public view returns (address);
function bytesOf(bytes32 _propertyName) public view returns (bytes);
function boolOf(bytes32 _propertyName) public view returns (bool);
function intOf(bytes32 _propertyName) public view returns (int);
function setUintProperty(bytes32 _propertyName, uint _value) public;
function setStringProperty(bytes32 _propertyName, string _value) public;
function setAddressProperty(bytes32 _propertyName, address _value) public;
function setBytesProperty(bytes32 _propertyName, bytes _value) public;
function setBoolProperty(bytes32 _propertyName, bool _value) public;
function setIntProperty(bytes32 _propertyName, int _value) public;
function getValueTypeOf(bytes32 _propertyName) public view returns (uint /* SettingsValueTypes */ );
event ChangeProperty(bytes32 indexed _propertyName, uint256 _type);
}
// File: contracts/interfaces/IAuthority.sol
pragma solidity ^0.4.24;
contract IAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
// File: contracts/DSAuth.sol
pragma solidity ^0.4.24;
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
/**
* @title DSAuth
* @dev The DSAuth contract is reference implement of https://github.com/dapphub/ds-auth
* But in the isAuthorized method, the src from address(this) is remove for safty concern.
*/
contract DSAuth is DSAuthEvents {
IAuthority public authority;
address public owner;
constructor() public {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
emit LogSetOwner(owner);
}
function setAuthority(IAuthority authority_)
public
auth
{
authority = authority_;
emit LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == owner) {
return true;
} else if (authority == IAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
// File: contracts/SettingIds.sol
pragma solidity ^0.4.24;
/**
Id definitions for SettingsRegistry.sol
Can be used in conjunction with the settings registry to get properties
*/
contract SettingIds {
bytes32 public constant CONTRACT_RING_ERC20_TOKEN = "CONTRACT_RING_ERC20_TOKEN";
bytes32 public constant CONTRACT_KTON_ERC20_TOKEN = "CONTRACT_KTON_ERC20_TOKEN";
bytes32 public constant CONTRACT_GOLD_ERC20_TOKEN = "CONTRACT_GOLD_ERC20_TOKEN";
bytes32 public constant CONTRACT_WOOD_ERC20_TOKEN = "CONTRACT_WOOD_ERC20_TOKEN";
bytes32 public constant CONTRACT_WATER_ERC20_TOKEN = "CONTRACT_WATER_ERC20_TOKEN";
bytes32 public constant CONTRACT_FIRE_ERC20_TOKEN = "CONTRACT_FIRE_ERC20_TOKEN";
bytes32 public constant CONTRACT_SOIL_ERC20_TOKEN = "CONTRACT_SOIL_ERC20_TOKEN";
bytes32 public constant CONTRACT_OBJECT_OWNERSHIP = "CONTRACT_OBJECT_OWNERSHIP";
bytes32 public constant CONTRACT_TOKEN_LOCATION = "CONTRACT_TOKEN_LOCATION";
bytes32 public constant CONTRACT_LAND_BASE = "CONTRACT_LAND_BASE";
bytes32 public constant CONTRACT_USER_POINTS = "CONTRACT_USER_POINTS";
bytes32 public constant CONTRACT_INTERSTELLAR_ENCODER = "CONTRACT_INTERSTELLAR_ENCODER";
bytes32 public constant CONTRACT_DIVIDENDS_POOL = "CONTRACT_DIVIDENDS_POOL";
bytes32 public constant CONTRACT_TOKEN_USE = "CONTRACT_TOKEN_USE";
bytes32 public constant CONTRACT_REVENUE_POOL = "CONTRACT_REVENUE_POOL";
bytes32 public constant CONTRACT_ERC721_BRIDGE = "CONTRACT_ERC721_BRIDGE";
bytes32 public constant CONTRACT_PET_BASE = "CONTRACT_PET_BASE";
// Cut owner takes on each auction, measured in basis points (1/100 of a percent).
// this can be considered as transaction fee.
// Values 0-10,000 map to 0%-100%
// set ownerCut to 4%
// ownerCut = 400;
bytes32 public constant UINT_AUCTION_CUT = "UINT_AUCTION_CUT"; // Denominator is 10000
bytes32 public constant UINT_TOKEN_OFFER_CUT = "UINT_TOKEN_OFFER_CUT"; // Denominator is 10000
// Cut referer takes on each auction, measured in basis points (1/100 of a percent).
// which cut from transaction fee.
// Values 0-10,000 map to 0%-100%
// set refererCut to 4%
// refererCut = 400;
bytes32 public constant UINT_REFERER_CUT = "UINT_REFERER_CUT";
bytes32 public constant CONTRACT_LAND_RESOURCE = "CONTRACT_LAND_RESOURCE";
}
// File: contracts/ObjectOwnership.sol
pragma solidity ^0.4.24;
contract ObjectOwnership is ERC721Token("Evolution Land Objects","EVO"), DSAuth, SettingIds {
ISettingsRegistry public registry;
bool private singletonLock = false;
/*
* Modifiers
*/
modifier singletonLockCall() {
require(!singletonLock, "Only can call once");
_;
singletonLock = true;
}
/**
* @dev Atlantis's constructor
*/
constructor () public {
// initializeContract();
}
/**
* @dev Same with constructor, but is used and called by storage proxy as logic contract.
*/
function initializeContract(address _registry) public singletonLockCall {
// Ownable constructor
owner = msg.sender;
emit LogSetOwner(msg.sender);
// SupportsInterfaceWithLookup constructor
_registerInterface(InterfaceId_ERC165);
// ERC721BasicToken constructor
_registerInterface(InterfaceId_ERC721);
_registerInterface(InterfaceId_ERC721Exists);
// ERC721Token constructor
name_ = "Evolution Land Objects";
symbol_ = "EVO"; // Evolution Land Objects
// register the supported interfaces to conform to ERC721 via ERC165
_registerInterface(InterfaceId_ERC721Enumerable);
_registerInterface(InterfaceId_ERC721Metadata);
registry = ISettingsRegistry(_registry);
}
function mintObject(address _to, uint128 _objectId) public auth returns (uint256 _tokenId) {
address interstellarEncoder = registry.addressOf(CONTRACT_INTERSTELLAR_ENCODER);
_tokenId = IInterstellarEncoder(interstellarEncoder).encodeTokenIdForObjectContract(
address(this), msg.sender, _objectId);
super._mint(_to, _tokenId);
}
function burnObject(address _to, uint128 _objectId) public auth returns (uint256 _tokenId) {
address interstellarEncoder = registry.addressOf(CONTRACT_INTERSTELLAR_ENCODER);
_tokenId = IInterstellarEncoder(interstellarEncoder).encodeTokenIdForObjectContract(
address(this), msg.sender, _objectId);
super._burn(_to, _tokenId);
}
function mint(address _to, uint256 _tokenId) public auth {
super._mint(_to, _tokenId);
}
function burn(address _to, uint256 _tokenId) public auth {
super._burn(_to, _tokenId);
}
//@dev user invoke approveAndCall to create auction
//@param _to - address of auction contractß
function approveAndCall(
address _to,
uint _tokenId,
bytes _extraData
) public {
// set _to to the auction contract
approve(_to, _tokenId);
if(!_to.call(
bytes4(keccak256("receiveApproval(address,uint256,bytes)")), abi.encode(msg.sender, _tokenId, _extraData)
)) {
revert();
}
}
}
// File: contracts/common/Proxy.sol
pragma solidity ^0.4.24;
/**
* @title Proxy
* @dev Gives the possibility to delegate any call to a foreign implementation.
*/
contract Proxy {
/**
* @dev Tells the address of the implementation where every call will be delegated.
* @return address of the implementation to which it will be delegated
*/
function implementation() public view returns (address);
/**
* @dev Fallback function allowing to perform a delegatecall to the given implementation.
* This function will return whatever the implementation call returns
*/
function () payable public {
address _impl = implementation();
require(_impl != address(0));
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize)
let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
let size := returndatasize
returndatacopy(ptr, 0, size)
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
}
// File: contracts/common/UpgradeabilityProxy.sol
pragma solidity ^0.4.24;
/**
* @title UpgradeabilityProxy
* @dev This contract represents a proxy where the implementation address to which it will delegate can be upgraded
*/
contract UpgradeabilityProxy is Proxy {
/**
* @dev This event will be emitted every time the implementation gets upgraded
* @param implementation representing the address of the upgraded implementation
*/
event Upgraded(address indexed implementation);
// Storage position of the address of the current implementation
bytes32 private constant implementationPosition = keccak256("org.zeppelinos.proxy.implementation");
/**
* @dev Constructor function
*/
function UpgradeabilityProxy() public {}
/**
* @dev Tells the address of the current implementation
* @return address of the current implementation
*/
function implementation() public view returns (address impl) {
bytes32 position = implementationPosition;
assembly {
impl := sload(position)
}
}
/**
* @dev Sets the address of the current implementation
* @param newImplementation address representing the new implementation to be set
*/
function setImplementation(address newImplementation) internal {
bytes32 position = implementationPosition;
assembly {
sstore(position, newImplementation)
}
}
/**
* @dev Upgrades the implementation address
* @param newImplementation representing the address of the new implementation to be set
*/
function _upgradeTo(address newImplementation) internal {
address currentImplementation = implementation();
require(currentImplementation != newImplementation);
setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
}
// File: contracts/common/OwnedUpgradeabilityProxy.sol
pragma solidity ^0.4.24;
/**
* @title OwnedUpgradeabilityProxy
* @dev This contract combines an upgradeability proxy with basic authorization control functionalities
*/
contract OwnedUpgradeabilityProxy is UpgradeabilityProxy {
/**
* @dev Event to show ownership has been transferred
* @param previousOwner representing the address of the previous owner
* @param newOwner representing the address of the new owner
*/
event ProxyOwnershipTransferred(address previousOwner, address newOwner);
// Storage position of the owner of the contract
bytes32 private constant proxyOwnerPosition = keccak256("org.zeppelinos.proxy.owner");
/**
* @dev the constructor sets the original owner of the contract to the sender account.
*/
function OwnedUpgradeabilityProxy() public {
setUpgradeabilityOwner(msg.sender);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyProxyOwner() {
require(msg.sender == proxyOwner());
_;
}
/**
* @dev Tells the address of the owner
* @return the address of the owner
*/
function proxyOwner() public view returns (address owner) {
bytes32 position = proxyOwnerPosition;
assembly {
owner := sload(position)
}
}
/**
* @dev Sets the address of the owner
*/
function setUpgradeabilityOwner(address newProxyOwner) internal {
bytes32 position = proxyOwnerPosition;
assembly {
sstore(position, newProxyOwner)
}
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferProxyOwnership(address newOwner) public onlyProxyOwner {
require(newOwner != address(0));
emit ProxyOwnershipTransferred(proxyOwner(), newOwner);
setUpgradeabilityOwner(newOwner);
}
/**
* @dev Allows the proxy owner to upgrade the current version of the proxy.
* @param implementation representing the address of the new implementation to be set.
*/
function upgradeTo(address implementation) public onlyProxyOwner {
_upgradeTo(implementation);
}
/**
* @dev Allows the proxy owner to upgrade the current version of the proxy and call the new implementation
* to initialize whatever is needed through a low level call.
* @param implementation representing the address of the new implementation to be set.
* @param data represents the msg.data to bet sent in the low level call. This parameter may include the function
* signature of the implementation to be called with the needed payload
*/
function upgradeToAndCall(address implementation, bytes data) payable public onlyProxyOwner {
upgradeTo(implementation);
require(this.call.value(msg.value)(data));
}
}
/**
*Submitted for verification at Etherscan.io on 2020-11-13
*/
// File: openzeppelin-solidity/contracts/math/SafeMath.sol
pragma solidity ^0.4.24;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
// Gas optimization: this is cheaper than asserting 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (_a == 0) {
return 0;
}
c = _a * _b;
assert(c / _a == _b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
// assert(_b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = _a / _b;
// assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
return _a / _b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
assert(_b <= _a);
return _a - _b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
c = _a + _b;
assert(c >= _a);
return c;
}
}
// File: openzeppelin-solidity/contracts/introspection/ERC165.sol
pragma solidity ^0.4.24;
/**
* @title ERC165
* @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
*/
interface ERC165 {
/**
* @notice Query if a contract implements an interface
* @param _interfaceId The interface identifier, as specified in ERC-165
* @dev Interface identification is specified in ERC-165. This function
* uses less than 30,000 gas.
*/
function supportsInterface(bytes4 _interfaceId)
external
view
returns (bool);
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721Basic.sol
pragma solidity ^0.4.24;
/**
* @title ERC721 Non-Fungible Token Standard basic interface
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Basic is ERC165 {
bytes4 internal constant InterfaceId_ERC721 = 0x80ac58cd;
/*
* 0x80ac58cd ===
* bytes4(keccak256('balanceOf(address)')) ^
* bytes4(keccak256('ownerOf(uint256)')) ^
* bytes4(keccak256('approve(address,uint256)')) ^
* bytes4(keccak256('getApproved(uint256)')) ^
* bytes4(keccak256('setApprovalForAll(address,bool)')) ^
* bytes4(keccak256('isApprovedForAll(address,address)')) ^
* bytes4(keccak256('transferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
*/
bytes4 internal constant InterfaceId_ERC721Exists = 0x4f558e79;
/*
* 0x4f558e79 ===
* bytes4(keccak256('exists(uint256)'))
*/
bytes4 internal constant InterfaceId_ERC721Enumerable = 0x780e9d63;
/**
* 0x780e9d63 ===
* bytes4(keccak256('totalSupply()')) ^
* bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^
* bytes4(keccak256('tokenByIndex(uint256)'))
*/
bytes4 internal constant InterfaceId_ERC721Metadata = 0x5b5e139f;
/**
* 0x5b5e139f ===
* bytes4(keccak256('name()')) ^
* bytes4(keccak256('symbol()')) ^
* bytes4(keccak256('tokenURI(uint256)'))
*/
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) public view returns (uint256 _balance);
function ownerOf(uint256 _tokenId) public view returns (address _owner);
function exists(uint256 _tokenId) public view returns (bool _exists);
function approve(address _to, uint256 _tokenId) public;
function getApproved(uint256 _tokenId)
public view returns (address _operator);
function setApprovalForAll(address _operator, bool _approved) public;
function isApprovedForAll(address _owner, address _operator)
public view returns (bool);
function transferFrom(address _from, address _to, uint256 _tokenId) public;
function safeTransferFrom(address _from, address _to, uint256 _tokenId)
public;
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes _data
)
public;
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721.sol
pragma solidity ^0.4.24;
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Enumerable is ERC721Basic {
function totalSupply() public view returns (uint256);
function tokenOfOwnerByIndex(
address _owner,
uint256 _index
)
public
view
returns (uint256 _tokenId);
function tokenByIndex(uint256 _index) public view returns (uint256);
}
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Metadata is ERC721Basic {
function name() external view returns (string _name);
function symbol() external view returns (string _symbol);
function tokenURI(uint256 _tokenId) public view returns (string);
}
/**
* @title ERC-721 Non-Fungible Token Standard, full implementation interface
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata {
}
// File: openzeppelin-solidity/contracts/introspection/SupportsInterfaceWithLookup.sol
pragma solidity ^0.4.24;
/**
* @title SupportsInterfaceWithLookup
* @author Matt Condon (@shrugs)
* @dev Implements ERC165 using a lookup table.
*/
contract SupportsInterfaceWithLookup is ERC165 {
bytes4 public constant InterfaceId_ERC165 = 0x01ffc9a7;
/**
* 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)'))
*/
/**
* @dev a mapping of interface id to whether or not it's supported
*/
mapping(bytes4 => bool) internal supportedInterfaces;
/**
* @dev A contract implementing SupportsInterfaceWithLookup
* implement ERC165 itself
*/
constructor()
public
{
_registerInterface(InterfaceId_ERC165);
}
/**
* @dev implement supportsInterface(bytes4) using a lookup table
*/
function supportsInterface(bytes4 _interfaceId)
external
view
returns (bool)
{
return supportedInterfaces[_interfaceId];
}
/**
* @dev private method for registering an interface
*/
function _registerInterface(bytes4 _interfaceId)
internal
{
require(_interfaceId != 0xffffffff);
supportedInterfaces[_interfaceId] = true;
}
}
// File: @evolutionland/common/contracts/interfaces/IMintableERC20.sol
pragma solidity ^0.4.23;
contract IMintableERC20 {
function mint(address _to, uint256 _value) public;
}
// File: @evolutionland/common/contracts/interfaces/ISettingsRegistry.sol
pragma solidity ^0.4.24;
contract ISettingsRegistry {
enum SettingsValueTypes { NONE, UINT, STRING, ADDRESS, BYTES, BOOL, INT }
function uintOf(bytes32 _propertyName) public view returns (uint256);
function stringOf(bytes32 _propertyName) public view returns (string);
function addressOf(bytes32 _propertyName) public view returns (address);
function bytesOf(bytes32 _propertyName) public view returns (bytes);
function boolOf(bytes32 _propertyName) public view returns (bool);
function intOf(bytes32 _propertyName) public view returns (int);
function setUintProperty(bytes32 _propertyName, uint _value) public;
function setStringProperty(bytes32 _propertyName, string _value) public;
function setAddressProperty(bytes32 _propertyName, address _value) public;
function setBytesProperty(bytes32 _propertyName, bytes _value) public;
function setBoolProperty(bytes32 _propertyName, bool _value) public;
function setIntProperty(bytes32 _propertyName, int _value) public;
function getValueTypeOf(bytes32 _propertyName) public view returns (uint /* SettingsValueTypes */ );
event ChangeProperty(bytes32 indexed _propertyName, uint256 _type);
}
// File: @evolutionland/common/contracts/interfaces/IAuthority.sol
pragma solidity ^0.4.24;
contract IAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
// File: @evolutionland/common/contracts/DSAuth.sol
pragma solidity ^0.4.24;
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
/**
* @title DSAuth
* @dev The DSAuth contract is reference implement of https://github.com/dapphub/ds-auth
* But in the isAuthorized method, the src from address(this) is remove for safty concern.
*/
contract DSAuth is DSAuthEvents {
IAuthority public authority;
address public owner;
constructor() public {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
emit LogSetOwner(owner);
}
function setAuthority(IAuthority authority_)
public
auth
{
authority = authority_;
emit LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == owner) {
return true;
} else if (authority == IAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
// File: @evolutionland/common/contracts/SettingIds.sol
pragma solidity ^0.4.24;
/**
Id definitions for SettingsRegistry.sol
Can be used in conjunction with the settings registry to get properties
*/
contract SettingIds {
bytes32 public constant CONTRACT_RING_ERC20_TOKEN = "CONTRACT_RING_ERC20_TOKEN";
bytes32 public constant CONTRACT_KTON_ERC20_TOKEN = "CONTRACT_KTON_ERC20_TOKEN";
bytes32 public constant CONTRACT_GOLD_ERC20_TOKEN = "CONTRACT_GOLD_ERC20_TOKEN";
bytes32 public constant CONTRACT_WOOD_ERC20_TOKEN = "CONTRACT_WOOD_ERC20_TOKEN";
bytes32 public constant CONTRACT_WATER_ERC20_TOKEN = "CONTRACT_WATER_ERC20_TOKEN";
bytes32 public constant CONTRACT_FIRE_ERC20_TOKEN = "CONTRACT_FIRE_ERC20_TOKEN";
bytes32 public constant CONTRACT_SOIL_ERC20_TOKEN = "CONTRACT_SOIL_ERC20_TOKEN";
bytes32 public constant CONTRACT_OBJECT_OWNERSHIP = "CONTRACT_OBJECT_OWNERSHIP";
bytes32 public constant CONTRACT_TOKEN_LOCATION = "CONTRACT_TOKEN_LOCATION";
bytes32 public constant CONTRACT_LAND_BASE = "CONTRACT_LAND_BASE";
bytes32 public constant CONTRACT_USER_POINTS = "CONTRACT_USER_POINTS";
bytes32 public constant CONTRACT_INTERSTELLAR_ENCODER = "CONTRACT_INTERSTELLAR_ENCODER";
bytes32 public constant CONTRACT_DIVIDENDS_POOL = "CONTRACT_DIVIDENDS_POOL";
bytes32 public constant CONTRACT_TOKEN_USE = "CONTRACT_TOKEN_USE";
bytes32 public constant CONTRACT_REVENUE_POOL = "CONTRACT_REVENUE_POOL";
bytes32 public constant CONTRACT_ERC721_BRIDGE = "CONTRACT_ERC721_BRIDGE";
bytes32 public constant CONTRACT_PET_BASE = "CONTRACT_PET_BASE";
// Cut owner takes on each auction, measured in basis points (1/100 of a percent).
// this can be considered as transaction fee.
// Values 0-10,000 map to 0%-100%
// set ownerCut to 4%
// ownerCut = 400;
bytes32 public constant UINT_AUCTION_CUT = "UINT_AUCTION_CUT"; // Denominator is 10000
bytes32 public constant UINT_TOKEN_OFFER_CUT = "UINT_TOKEN_OFFER_CUT"; // Denominator is 10000
// Cut referer takes on each auction, measured in basis points (1/100 of a percent).
// which cut from transaction fee.
// Values 0-10,000 map to 0%-100%
// set refererCut to 4%
// refererCut = 400;
bytes32 public constant UINT_REFERER_CUT = "UINT_REFERER_CUT";
bytes32 public constant CONTRACT_LAND_RESOURCE = "CONTRACT_LAND_RESOURCE";
}
// File: @evolutionland/common/contracts/interfaces/IInterstellarEncoder.sol
pragma solidity ^0.4.24;
contract IInterstellarEncoder {
uint256 constant CLEAR_HIGH = 0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff;
uint256 public constant MAGIC_NUMBER = 42; // Interstellar Encoding Magic Number.
uint256 public constant CHAIN_ID = 1; // Ethereum mainet.
uint256 public constant CURRENT_LAND = 1; // 1 is Atlantis, 0 is NaN.
enum ObjectClass {
NaN,
LAND,
APOSTLE,
OBJECT_CLASS_COUNT
}
function registerNewObjectClass(address _objectContract, uint8 objectClass) public;
function registerNewTokenContract(address _tokenAddress) public;
function encodeTokenId(address _tokenAddress, uint8 _objectClass, uint128 _objectIndex) public view returns (uint256 _tokenId);
function encodeTokenIdForObjectContract(
address _tokenAddress, address _objectContract, uint128 _objectId) public view returns (uint256 _tokenId);
function getContractAddress(uint256 _tokenId) public view returns (address);
function getObjectId(uint256 _tokenId) public view returns (uint128 _objectId);
function getObjectClass(uint256 _tokenId) public view returns (uint8);
function getObjectAddress(uint256 _tokenId) public view returns (address);
}
// File: @evolutionland/common/contracts/interfaces/ITokenUse.sol
pragma solidity ^0.4.24;
contract ITokenUse {
uint48 public constant MAX_UINT48_TIME = 281474976710655;
function isObjectInHireStage(uint256 _tokenId) public view returns (bool);
function isObjectReadyToUse(uint256 _tokenId) public view returns (bool);
function getTokenUser(uint256 _tokenId) public view returns (address);
function createTokenUseOffer(uint256 _tokenId, uint256 _duration, uint256 _price, address _acceptedActivity) public;
function cancelTokenUseOffer(uint256 _tokenId) public;
function takeTokenUseOffer(uint256 _tokenId) public;
function addActivity(uint256 _tokenId, address _user, uint256 _endTime) public;
function removeActivity(uint256 _tokenId, address _user) public;
}
// File: @evolutionland/common/contracts/interfaces/IActivity.sol
pragma solidity ^0.4.24;
contract IActivity is ERC165 {
bytes4 internal constant InterfaceId_IActivity = 0x6086e7f8;
/*
* 0x6086e7f8 ===
* bytes4(keccak256('activityStopped(uint256)'))
*/
function activityStopped(uint256 _tokenId) public;
}
// File: @evolutionland/common/contracts/interfaces/IMinerObject.sol
pragma solidity ^0.4.24;
contract IMinerObject is ERC165 {
bytes4 internal constant InterfaceId_IMinerObject = 0x64272b75;
/*
* 0x64272b752 ===
* bytes4(keccak256('strengthOf(uint256,address)'))
*/
function strengthOf(uint256 _tokenId, address _resourceToken, uint256 _landTokenId) public view returns (uint256);
}
// File: contracts/interfaces/ILandBase.sol
pragma solidity ^0.4.24;
contract ILandBase {
/*
* Event
*/
event ModifiedResourceRate(uint indexed tokenId, address resourceToken, uint16 newResourceRate);
event HasboxSetted(uint indexed tokenId, bool hasBox);
event ChangedReourceRateAttr(uint indexed tokenId, uint256 attr);
event ChangedFlagMask(uint indexed tokenId, uint256 newFlagMask);
event CreatedNewLand(uint indexed tokenId, int x, int y, address beneficiary, uint256 resourceRateAttr, uint256 mask);
function defineResouceTokenRateAttrId(address _resourceToken, uint8 _attrId) public;
function setHasBox(uint _landTokenID, bool isHasBox) public;
function isReserved(uint256 _tokenId) public view returns (bool);
function isSpecial(uint256 _tokenId) public view returns (bool);
function isHasBox(uint256 _tokenId) public view returns (bool);
function getResourceRateAttr(uint _landTokenId) public view returns (uint256);
function setResourceRateAttr(uint _landTokenId, uint256 _newResourceRateAttr) public;
function getResourceRate(uint _landTokenId, address _resouceToken) public view returns (uint16);
function setResourceRate(uint _landTokenID, address _resourceToken, uint16 _newResouceRate) public;
function getFlagMask(uint _landTokenId) public view returns (uint256);
function setFlagMask(uint _landTokenId, uint256 _newFlagMask) public;
}
// File: contracts/LandSettingIds.sol
pragma solidity ^0.4.24;
contract LandSettingIds is SettingIds {
}
// File: contracts/LandResourceV4.sol
pragma solidity ^0.4.23;
/**
* @title LandResource
* @dev LandResource is registry that manage the element resources generated on Land, and related resource releasing speed.
* difference between LandResourceV2:
1. add function landWorkingOn to get which land the apostle is working on
2. add function updateMinerStrength to update miner strength on land
3. add event UpdateMiningStrength
*/
contract LandResourceV4 is SupportsInterfaceWithLookup, DSAuth, IActivity, LandSettingIds {
using SafeMath for *;
// For every seconds, the speed will decrease by current speed multiplying (DENOMINATOR_in_seconds - seconds) / DENOMINATOR_in_seconds
// resource will decrease 1/10000 every day.
uint256 public constant DENOMINATOR = 10000;
uint256 public constant TOTAL_SECONDS = DENOMINATOR * (1 days);
bool private singletonLock = false;
ISettingsRegistry public registry;
uint256 public resourceReleaseStartTime;
// TODO: move to global settings contract.
uint256 public attenPerDay = 1;
uint256 public recoverAttenPerDay = 20;
// Struct for recording resouces on land which have already been pinged.
// 金, Evolution Land Gold
// 木, Evolution Land Wood
// 水, Evolution Land Water
// 火, Evolution Land fire
// 土, Evolution Land Silicon
struct ResourceMineState {
mapping(address => uint256) mintedBalance;
mapping(address => uint256[]) miners;
mapping(address => uint256) totalMinerStrength;
uint256 lastUpdateSpeedInSeconds;
uint256 lastDestoryAttenInSeconds;
uint256 industryIndex;
uint128 lastUpdateTime;
uint64 totalMiners;
uint64 maxMiners;
}
struct MinerStatus {
uint256 landTokenId;
address resource;
uint64 indexInResource;
}
mapping(uint256 => ResourceMineState) public land2ResourceMineState;
mapping(uint256 => MinerStatus) public miner2Index;
/*
* Event
*/
event StartMining(uint256 minerTokenId, uint256 landTokenId, address _resource, uint256 strength);
event StopMining(uint256 minerTokenId, uint256 landTokenId, address _resource, uint256 strength);
event ResourceClaimed(address owner, uint256 landTokenId, uint256 goldBalance, uint256 woodBalance, uint256 waterBalance, uint256 fireBalance, uint256 soilBalance);
event UpdateMiningStrengthWhenStop(uint256 apostleTokenId, uint256 landTokenId, uint256 strength);
event UpdateMiningStrengthWhenStart(uint256 apostleTokenId, uint256 landTokenId, uint256 strength);
/*
* Modifiers
*/
modifier singletonLockCall() {
require(!singletonLock, "Only can call once");
_;
singletonLock = true;
}
function initializeContract(address _registry, uint256 _resourceReleaseStartTime) public singletonLockCall {
// Ownable constructor
owner = msg.sender;
emit LogSetOwner(msg.sender);
registry = ISettingsRegistry(_registry);
resourceReleaseStartTime = _resourceReleaseStartTime;
_registerInterface(InterfaceId_IActivity);
}
// get amount of speed uint at this moment
function _getReleaseSpeedInSeconds(uint256 _tokenId, uint256 _time) internal view returns (uint256 currentSpeed) {
require(_time >= resourceReleaseStartTime, "Should after release time");
require(_time >= land2ResourceMineState[_tokenId].lastUpdateTime, "Should after release last update time");
// after 10000 days from start
// the resource release speed decreases to 0
if (TOTAL_SECONDS < _time - resourceReleaseStartTime)
{
return 0;
}
// max amount of speed unit of _tokenId for now
// suppose that speed_uint = 1 in this function
uint256 availableSpeedInSeconds = TOTAL_SECONDS.sub(_time - resourceReleaseStartTime);
// time from last update
uint256 timeBetween = _time - land2ResourceMineState[_tokenId].lastUpdateTime;
// the recover speed is 20/10000, 20 times.
// recoveryRate overall from lasUpdateTime til now + amount of speed uint at lastUpdateTime
uint256 nextSpeedInSeconds = land2ResourceMineState[_tokenId].lastUpdateSpeedInSeconds + timeBetween * recoverAttenPerDay;
// destroyRate overall from lasUpdateTime til now amount of speed uint at lastUpdateTime
uint256 destroyedSpeedInSeconds = timeBetween * land2ResourceMineState[_tokenId].lastDestoryAttenInSeconds;
if (nextSpeedInSeconds < destroyedSpeedInSeconds)
{
nextSpeedInSeconds = 0;
} else {
nextSpeedInSeconds = nextSpeedInSeconds - destroyedSpeedInSeconds;
}
if (nextSpeedInSeconds > availableSpeedInSeconds) {
nextSpeedInSeconds = availableSpeedInSeconds;
}
return nextSpeedInSeconds;
}
function getReleaseSpeed(uint256 _tokenId, address _resourceToken, uint256 _time) public view returns (uint256 currentSpeed) {
return ILandBase(registry.addressOf(CONTRACT_LAND_BASE))
.getResourceRate(_tokenId, _resourceToken).mul(_getReleaseSpeedInSeconds(_tokenId, _time))
.div(TOTAL_SECONDS);
}
/**
* @dev Get and Query the amount of resources available from lastUpdateTime to now for use on specific land.
* @param _tokenId The token id of specific land.
*/
function _getMinableBalance(uint256 _tokenId, address _resourceToken, uint256 _currentTime, uint256 _lastUpdateTime) public view returns (uint256 minableBalance) {
uint256 speed_in_current_period = ILandBase(registry.addressOf(CONTRACT_LAND_BASE))
.getResourceRate(_tokenId, _resourceToken).mul(_getReleaseSpeedInSeconds(_tokenId, ((_currentTime + _lastUpdateTime) / 2))).mul(1 ether).div(1 days).div(TOTAL_SECONDS);
// calculate the area of trapezoid
minableBalance = speed_in_current_period.mul(_currentTime - _lastUpdateTime);
}
function _getMaxMineBalance(uint256 _tokenId, address _resourceToken, uint256 _currentTime, uint256 _lastUpdateTime) internal view returns (uint256) {
// totalMinerStrength is in wei
uint256 mineSpeed = land2ResourceMineState[_tokenId].totalMinerStrength[_resourceToken];
return mineSpeed.mul(_currentTime - _lastUpdateTime).div(1 days);
}
function mine(uint256 _landTokenId) public {
_mineAllResource(
_landTokenId,
registry.addressOf(CONTRACT_GOLD_ERC20_TOKEN),
registry.addressOf(CONTRACT_WOOD_ERC20_TOKEN),
registry.addressOf(CONTRACT_WATER_ERC20_TOKEN),
registry.addressOf(CONTRACT_FIRE_ERC20_TOKEN),
registry.addressOf(CONTRACT_SOIL_ERC20_TOKEN)
);
}
function _mineAllResource(uint256 _landTokenId, address _gold, address _wood, address _water, address _fire, address _soil) internal {
require(IInterstellarEncoder(registry.addressOf(CONTRACT_INTERSTELLAR_ENCODER)).getObjectClass(_landTokenId) == 1, "Token must be land.");
if (land2ResourceMineState[_landTokenId].lastUpdateTime == 0) {
land2ResourceMineState[_landTokenId].lastUpdateTime = uint128(resourceReleaseStartTime);
land2ResourceMineState[_landTokenId].lastUpdateSpeedInSeconds = TOTAL_SECONDS;
}
_mineResource(_landTokenId, _gold);
_mineResource(_landTokenId, _wood);
_mineResource(_landTokenId, _water);
_mineResource(_landTokenId, _fire);
_mineResource(_landTokenId, _soil);
land2ResourceMineState[_landTokenId].lastUpdateSpeedInSeconds = _getReleaseSpeedInSeconds(_landTokenId, now);
land2ResourceMineState[_landTokenId].lastUpdateTime = uint128(now);
}
function _mineResource(uint256 _landTokenId, address _resourceToken) internal {
// the longest seconds to zero speed.
uint minedBalance = _calculateMinedBalance(_landTokenId, _resourceToken, now);
land2ResourceMineState[_landTokenId].mintedBalance[_resourceToken] += minedBalance;
}
function _calculateMinedBalance(uint256 _landTokenId, address _resourceToken, uint256 _currentTime) internal returns (uint256) {
uint256 currentTime = _currentTime;
uint256 minedBalance;
uint256 minableBalance;
if (currentTime > (resourceReleaseStartTime + TOTAL_SECONDS))
{
currentTime = (resourceReleaseStartTime + TOTAL_SECONDS);
}
uint256 lastUpdateTime = land2ResourceMineState[_landTokenId].lastUpdateTime;
require(currentTime >= lastUpdateTime);
if (lastUpdateTime >= (resourceReleaseStartTime + TOTAL_SECONDS)) {
minedBalance = 0;
minableBalance = 0;
} else {
minedBalance = _getMaxMineBalance(_landTokenId, _resourceToken, currentTime, lastUpdateTime);
minableBalance = _getMinableBalance(_landTokenId, _resourceToken, currentTime, lastUpdateTime);
}
if (minedBalance > minableBalance) {
minedBalance = minableBalance;
}
return minedBalance;
}
function claimAllResource(uint256 _landTokenId) public {
require(msg.sender == ERC721(registry.addressOf(CONTRACT_OBJECT_OWNERSHIP)).ownerOf(_landTokenId), "Must be the owner of the land");
address gold = registry.addressOf(CONTRACT_GOLD_ERC20_TOKEN);
address wood = registry.addressOf(CONTRACT_WOOD_ERC20_TOKEN);
address water = registry.addressOf(CONTRACT_WATER_ERC20_TOKEN);
address fire = registry.addressOf(CONTRACT_FIRE_ERC20_TOKEN);
address soil = registry.addressOf(CONTRACT_SOIL_ERC20_TOKEN);
_mineAllResource(_landTokenId, gold, wood, water, fire, soil);
uint goldBalance;
uint woodBalance;
uint waterBalance;
uint fireBalance;
uint soilBalance;
if (land2ResourceMineState[_landTokenId].mintedBalance[gold] > 0) {
goldBalance = land2ResourceMineState[_landTokenId].mintedBalance[gold];
IMintableERC20(gold).mint(msg.sender, goldBalance);
land2ResourceMineState[_landTokenId].mintedBalance[gold] = 0;
}
if (land2ResourceMineState[_landTokenId].mintedBalance[wood] > 0) {
woodBalance = land2ResourceMineState[_landTokenId].mintedBalance[wood];
IMintableERC20(wood).mint(msg.sender, woodBalance);
land2ResourceMineState[_landTokenId].mintedBalance[wood] = 0;
}
if (land2ResourceMineState[_landTokenId].mintedBalance[water] > 0) {
waterBalance = land2ResourceMineState[_landTokenId].mintedBalance[water];
IMintableERC20(water).mint(msg.sender, waterBalance);
land2ResourceMineState[_landTokenId].mintedBalance[water] = 0;
}
if (land2ResourceMineState[_landTokenId].mintedBalance[fire] > 0) {
fireBalance = land2ResourceMineState[_landTokenId].mintedBalance[fire];
IMintableERC20(fire).mint(msg.sender, fireBalance);
land2ResourceMineState[_landTokenId].mintedBalance[fire] = 0;
}
if (land2ResourceMineState[_landTokenId].mintedBalance[soil] > 0) {
soilBalance = land2ResourceMineState[_landTokenId].mintedBalance[soil];
IMintableERC20(soil).mint(msg.sender, soilBalance);
land2ResourceMineState[_landTokenId].mintedBalance[soil] = 0;
}
emit ResourceClaimed(msg.sender, _landTokenId, goldBalance, woodBalance, waterBalance, fireBalance, soilBalance);
}
// both for own _tokenId or hired one
function startMining(uint256 _tokenId, uint256 _landTokenId, address _resource) public {
ITokenUse tokenUse = ITokenUse(registry.addressOf(CONTRACT_TOKEN_USE));
tokenUse.addActivity(_tokenId, msg.sender, 0);
// require the permission from land owner;
require(msg.sender == ERC721(registry.addressOf(CONTRACT_OBJECT_OWNERSHIP)).ownerOf(_landTokenId), "Must be the owner of the land");
// make sure that _tokenId won't be used repeatedly
require(miner2Index[_tokenId].landTokenId == 0);
// update status!
mine(_landTokenId);
uint256 _index = land2ResourceMineState[_landTokenId].miners[_resource].length;
land2ResourceMineState[_landTokenId].totalMiners += 1;
if (land2ResourceMineState[_landTokenId].maxMiners == 0) {
land2ResourceMineState[_landTokenId].maxMiners = 5;
}
require(land2ResourceMineState[_landTokenId].totalMiners <= land2ResourceMineState[_landTokenId].maxMiners);
address miner = IInterstellarEncoder(registry.addressOf(CONTRACT_INTERSTELLAR_ENCODER)).getObjectAddress(_tokenId);
uint256 strength = IMinerObject(miner).strengthOf(_tokenId, _resource, _landTokenId);
land2ResourceMineState[_landTokenId].miners[_resource].push(_tokenId);
land2ResourceMineState[_landTokenId].totalMinerStrength[_resource] += strength;
miner2Index[_tokenId] = MinerStatus({
landTokenId : _landTokenId,
resource : _resource,
indexInResource : uint64(_index)
});
emit StartMining(_tokenId, _landTokenId, _resource, strength);
}
function batchStartMining(uint256[] _tokenIds, uint256[] _landTokenIds, address[] _resources) public {
require(_tokenIds.length == _landTokenIds.length && _landTokenIds.length == _resources.length, "input error");
uint length = _tokenIds.length;
for (uint i = 0; i < length; i++) {
startMining(_tokenIds[i], _landTokenIds[i], _resources[i]);
}
}
function batchClaimAllResource(uint256[] _landTokenIds) public {
uint length = _landTokenIds.length;
for (uint i = 0; i < length; i++) {
claimAllResource(_landTokenIds[i]);
}
}
// Only trigger from Token Activity.
function activityStopped(uint256 _tokenId) public auth {
_stopMining(_tokenId);
}
function stopMining(uint256 _tokenId) public {
ITokenUse(registry.addressOf(CONTRACT_TOKEN_USE)).removeActivity(_tokenId, msg.sender);
}
function _stopMining(uint256 _tokenId) internal {
// remove the miner from land2ResourceMineState;
uint64 minerIndex = miner2Index[_tokenId].indexInResource;
address resource = miner2Index[_tokenId].resource;
uint256 landTokenId = miner2Index[_tokenId].landTokenId;
// update status!
mine(landTokenId);
uint64 lastMinerIndex = uint64(land2ResourceMineState[landTokenId].miners[resource].length.sub(1));
uint256 lastMiner = land2ResourceMineState[landTokenId].miners[resource][lastMinerIndex];
land2ResourceMineState[landTokenId].miners[resource][minerIndex] = lastMiner;
land2ResourceMineState[landTokenId].miners[resource][lastMinerIndex] = 0;
land2ResourceMineState[landTokenId].miners[resource].length -= 1;
miner2Index[lastMiner].indexInResource = minerIndex;
land2ResourceMineState[landTokenId].totalMiners -= 1;
address miner = IInterstellarEncoder(registry.addressOf(CONTRACT_INTERSTELLAR_ENCODER)).getObjectAddress(_tokenId);
uint256 strength = IMinerObject(miner).strengthOf(_tokenId, resource, landTokenId);
// for backward compatibility
// if strength can fluctuate some time in the future
if (land2ResourceMineState[landTokenId].totalMinerStrength[resource] != 0) {
if (land2ResourceMineState[landTokenId].totalMinerStrength[resource] > strength) {
land2ResourceMineState[landTokenId].totalMinerStrength[resource] = land2ResourceMineState[landTokenId].totalMinerStrength[resource].sub(strength);
} else {
land2ResourceMineState[landTokenId].totalMinerStrength[resource] = 0;
}
}
if (land2ResourceMineState[landTokenId].totalMiners == 0) {
land2ResourceMineState[landTokenId].totalMinerStrength[resource] = 0;
}
delete miner2Index[_tokenId];
emit StopMining(_tokenId, landTokenId, resource, strength);
}
function getMinerOnLand(uint _landTokenId, address _resourceToken, uint _index) public view returns (uint256) {
return land2ResourceMineState[_landTokenId].miners[_resourceToken][_index];
}
function getTotalMiningStrength(uint _landTokenId, address _resourceToken) public view returns (uint256) {
return land2ResourceMineState[_landTokenId].totalMinerStrength[_resourceToken];
}
function availableResources(uint256 _landTokenId, address[5] _resourceTokens) public view returns (uint256, uint256, uint256, uint256, uint256) {
uint availableGold = _calculateMinedBalance(_landTokenId, _resourceTokens[0], now) + land2ResourceMineState[_landTokenId].mintedBalance[_resourceTokens[0]];
uint availableWood = _calculateMinedBalance(_landTokenId, _resourceTokens[1], now) + land2ResourceMineState[_landTokenId].mintedBalance[_resourceTokens[1]];
uint availableWater = _calculateMinedBalance(_landTokenId, _resourceTokens[2], now) + land2ResourceMineState[_landTokenId].mintedBalance[_resourceTokens[2]];
uint availableFire = _calculateMinedBalance(_landTokenId, _resourceTokens[3], now) + land2ResourceMineState[_landTokenId].mintedBalance[_resourceTokens[3]];
uint availableSoil = _calculateMinedBalance(_landTokenId, _resourceTokens[4], now) + land2ResourceMineState[_landTokenId].mintedBalance[_resourceTokens[4]];
return (availableGold, availableWood, availableWater, availableFire, availableSoil);
}
function mintedBalanceOnLand(uint256 _landTokenId, address _resourceToken) public view returns (uint256) {
return land2ResourceMineState[_landTokenId].mintedBalance[_resourceToken];
}
function landWorkingOn(uint256 _apostleTokenId) public view returns (uint256 landTokenId) {
landTokenId = miner2Index[_apostleTokenId].landTokenId;
}
function _updateMinerStrength(uint256 _apostleTokenId, bool _isStop) internal returns (uint256, uint256){
// require that this apostle
uint256 landTokenId = landWorkingOn(_apostleTokenId);
require(landTokenId != 0, "this apostle is not mining.");
address resource = miner2Index[_apostleTokenId].resource;
address miner = IInterstellarEncoder(registry.addressOf(CONTRACT_INTERSTELLAR_ENCODER)).getObjectAddress(_apostleTokenId);
uint256 strength = IMinerObject(miner).strengthOf(_apostleTokenId, resource, landTokenId);
mine(landTokenId);
if (_isStop) {
land2ResourceMineState[landTokenId].totalMinerStrength[resource] = land2ResourceMineState[landTokenId].totalMinerStrength[resource].sub(strength);
} else {
land2ResourceMineState[landTokenId].totalMinerStrength[resource] += strength;
}
return (landTokenId, strength);
}
// when a mirrorToken or a pet has tied to apostle
// we need to update status and remove this apostle from mining list first
// open authority to PetBase
// can only be called by PetBase
function updateMinerStrengthWhenStop(uint256 _apostleTokenId) public auth {
uint256 landTokenId;
uint256 strength;
(landTokenId, strength) = _updateMinerStrength(_apostleTokenId, true);
// _isStop == true - minus strength
// _isStop == false - add strength
emit UpdateMiningStrengthWhenStop(_apostleTokenId, landTokenId, strength);
}
function updateMinerStrengthWhenStart(uint256 _apostleTokenId) public auth {
uint256 landTokenId;
uint256 strength;
(landTokenId, strength) = _updateMinerStrength(_apostleTokenId, false);
// _isStop == true - minus strength
// _isStop == false - add strength
emit UpdateMiningStrengthWhenStart(_apostleTokenId, landTokenId, strength);
}
}
// File: lib/ds-token/lib/ds-stop/lib/ds-auth/src/auth.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.4.23;
contract DSAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
contract DSAuth is DSAuthEvents {
DSAuthority public authority;
address public owner;
constructor() public {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
emit LogSetOwner(owner);
}
function setAuthority(DSAuthority authority_)
public
auth
{
authority = authority_;
emit LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == address(this)) {
return true;
} else if (src == owner) {
return true;
} else if (authority == DSAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
// File: lib/ds-token/lib/ds-stop/lib/ds-note/src/note.sol
/// note.sol -- the `note' modifier, for logging calls as events
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.4.23;
contract DSNote {
event LogNote(
bytes4 indexed sig,
address indexed guy,
bytes32 indexed foo,
bytes32 indexed bar,
uint wad,
bytes fax
) anonymous;
modifier note {
bytes32 foo;
bytes32 bar;
assembly {
foo := calldataload(4)
bar := calldataload(36)
}
emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
_;
}
}
// File: lib/ds-token/lib/ds-stop/src/stop.sol
/// stop.sol -- mixin for enable/disable functionality
// Copyright (C) 2017 DappHub, LLC
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.4.23;
contract DSStop is DSNote, DSAuth {
bool public stopped;
modifier stoppable {
require(!stopped);
_;
}
function stop() public auth note {
stopped = true;
}
function start() public auth note {
stopped = false;
}
}
// File: lib/ds-token/lib/erc20/src/erc20.sol
/// erc20.sol -- API for the ERC20 token standard
// See <https://github.com/ethereum/EIPs/issues/20>.
// This file likely does not meet the threshold of originality
// required for copyright to apply. As a result, this is free and
// unencumbered software belonging to the public domain.
pragma solidity ^0.4.8;
contract ERC20Events {
event Approval(address indexed src, address indexed guy, uint wad);
event Transfer(address indexed src, address indexed dst, uint wad);
}
contract ERC20 is ERC20Events {
function totalSupply() public view returns (uint);
function balanceOf(address guy) public view returns (uint);
function allowance(address src, address guy) public view returns (uint);
function approve(address guy, uint wad) public returns (bool);
function transfer(address dst, uint wad) public returns (bool);
function transferFrom(
address src, address dst, uint wad
) public returns (bool);
}
// File: lib/ds-token/lib/ds-math/src/math.sol
/// math.sol -- mixin for inline numerical wizardry
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.4.13;
contract DSMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x);
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x);
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x);
}
function min(uint x, uint y) internal pure returns (uint z) {
return x <= y ? x : y;
}
function max(uint x, uint y) internal pure returns (uint z) {
return x >= y ? x : y;
}
function imin(int x, int y) internal pure returns (int z) {
return x <= y ? x : y;
}
function imax(int x, int y) internal pure returns (int z) {
return x >= y ? x : y;
}
uint constant WAD = 10 ** 18;
uint constant RAY = 10 ** 27;
function wmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), WAD / 2) / WAD;
}
function rmul(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
function wdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, WAD), y / 2) / y;
}
function rdiv(uint x, uint y) internal pure returns (uint z) {
z = add(mul(x, RAY), y / 2) / y;
}
// This famous algorithm is called "exponentiation by squaring"
// and calculates x^n with x as fixed-point and n as regular unsigned.
//
// It's O(log n), instead of O(n) for naive repeated multiplication.
//
// These facts are why it works:
//
// If n is even, then x^n = (x^2)^(n/2).
// If n is odd, then x^n = x * x^(n-1),
// and applying the equation for even x gives
// x^n = x * (x^2)^((n-1) / 2).
//
// Also, EVM division is flooring and
// floor[(n-1) / 2] = floor[n / 2].
//
function rpow(uint x, uint n) internal pure returns (uint z) {
z = n % 2 != 0 ? x : RAY;
for (n /= 2; n != 0; n /= 2) {
x = rmul(x, x);
if (n % 2 != 0) {
z = rmul(z, x);
}
}
}
}
// File: lib/ds-token/src/base.sol
/// base.sol -- basic ERC20 implementation
// Copyright (C) 2015, 2016, 2017 DappHub, LLC
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.4.23;
contract DSTokenBase is ERC20, DSMath {
uint256 _supply;
mapping (address => uint256) _balances;
mapping (address => mapping (address => uint256)) _approvals;
constructor(uint supply) public {
_balances[msg.sender] = supply;
_supply = supply;
}
function totalSupply() public view returns (uint) {
return _supply;
}
function balanceOf(address src) public view returns (uint) {
return _balances[src];
}
function allowance(address src, address guy) public view returns (uint) {
return _approvals[src][guy];
}
function transfer(address dst, uint wad) public returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(address src, address dst, uint wad)
public
returns (bool)
{
if (src != msg.sender) {
_approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
}
_balances[src] = sub(_balances[src], wad);
_balances[dst] = add(_balances[dst], wad);
emit Transfer(src, dst, wad);
return true;
}
function approve(address guy, uint wad) public returns (bool) {
_approvals[msg.sender][guy] = wad;
emit Approval(msg.sender, guy, wad);
return true;
}
}
// File: lib/ds-token/src/token.sol
/// token.sol -- ERC20 implementation with minting and burning
// Copyright (C) 2015, 2016, 2017 DappHub, LLC
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.4.23;
contract DSToken is DSTokenBase(0), DSStop {
bytes32 public symbol;
uint256 public decimals = 18; // standard token precision. override to customize
constructor(bytes32 symbol_) public {
symbol = symbol_;
}
event Mint(address indexed guy, uint wad);
event Burn(address indexed guy, uint wad);
function approve(address guy) public stoppable returns (bool) {
return super.approve(guy, uint(-1));
}
function approve(address guy, uint wad) public stoppable returns (bool) {
return super.approve(guy, wad);
}
function transferFrom(address src, address dst, uint wad)
public
stoppable
returns (bool)
{
if (src != msg.sender && _approvals[src][msg.sender] != uint(-1)) {
_approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
}
_balances[src] = sub(_balances[src], wad);
_balances[dst] = add(_balances[dst], wad);
emit Transfer(src, dst, wad);
return true;
}
function push(address dst, uint wad) public {
transferFrom(msg.sender, dst, wad);
}
function pull(address src, uint wad) public {
transferFrom(src, msg.sender, wad);
}
function move(address src, address dst, uint wad) public {
transferFrom(src, dst, wad);
}
function mint(uint wad) public {
mint(msg.sender, wad);
}
function burn(uint wad) public {
burn(msg.sender, wad);
}
function mint(address guy, uint wad) public auth stoppable {
_balances[guy] = add(_balances[guy], wad);
_supply = add(_supply, wad);
emit Mint(guy, wad);
}
function burn(address guy, uint wad) public auth stoppable {
if (guy != msg.sender && _approvals[guy][msg.sender] != uint(-1)) {
_approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad);
}
_balances[guy] = sub(_balances[guy], wad);
_supply = sub(_supply, wad);
emit Burn(guy, wad);
}
// Optional token name
bytes32 public name = "";
function setName(bytes32 name_) public auth {
name = name_;
}
}
// File: evolutionlandcommon/contracts/interfaces/ERC223ReceivingContract.sol
pragma solidity ^0.4.23;
/*
* Contract that is working with ERC223 tokens
* https://github.com/ethereum/EIPs/issues/223
*/
/// @title ERC223ReceivingContract - Standard contract implementation for compatibility with ERC223 tokens.
interface ERC223ReceivingContract {
/// @dev Function that is called when a user or another contract wants to transfer funds.
/// @param _from Transaction initiator, analogue of msg.sender
/// @param _value Number of tokens to transfer.
/// @param _data Data containig a function signature and/or parameters
function tokenFallback(address _from, uint256 _value, bytes _data) public;
}
// File: evolutionlandcommon/contracts/interfaces/TokenController.sol
pragma solidity ^0.4.23;
/// @dev The token controller contract must implement these functions
contract TokenController {
/// @notice Called when `_owner` sends ether to the MiniMe Token contract
/// @param _owner The address that sent the ether to create tokens
/// @return True if the ether is accepted, false if it throws
function proxyPayment(address _owner, bytes4 sig, bytes data) payable public returns (bool);
/// @notice Notifies the controller about a token transfer allowing the
/// controller to react if desired
/// @param _from The origin of the transfer
/// @param _to The destination of the transfer
/// @param _amount The amount of the transfer
/// @return False if the controller does not authorize the transfer
function onTransfer(address _from, address _to, uint _amount) public returns (bool);
/// @notice Notifies the controller about an approval allowing the
/// controller to react if desired
/// @param _owner The address that calls `approve()`
/// @param _spender The spender in the `approve()` call
/// @param _amount The amount in the `approve()` call
/// @return False if the controller does not authorize the approval
function onApprove(address _owner, address _spender, uint _amount) public returns (bool);
}
// File: evolutionlandcommon/contracts/interfaces/ApproveAndCallFallBack.sol
pragma solidity ^0.4.23;
interface ApproveAndCallFallBack {
function receiveApproval(address from, uint256 _amount, address _token, bytes _data) public;
}
// File: evolutionlandcommon/contracts/interfaces/ERC223.sol
pragma solidity ^0.4.23;
interface ERC223 {
function transfer(address to, uint amount, bytes data) public returns (bool ok);
function transferFrom(address from, address to, uint256 amount, bytes data) public returns (bool ok);
event ERC223Transfer(address indexed from, address indexed to, uint amount, bytes data);
}
// File: evolutionlandcommon/contracts/interfaces/ISmartToken.sol
pragma solidity ^0.4.23;
/*
Smart Token interface
*/
contract ISmartToken {
function transferOwnership(address _newOwner) public;
function acceptOwnership() public;
function disableTransfers(bool _disable) public;
function issue(address _to, uint256 _amount) public;
function destroy(address _from, uint256 _amount) public;
}
// File: src/RING.sol
pragma solidity ^0.4.23;
contract RING is DSToken("RING"), ERC223, ISmartToken {
address public newOwner;
bool public transfersEnabled = true; // true if transfer/transferFrom are enabled, false if not
uint256 public cap;
address public controller;
// allows execution only when transfers aren't disabled
modifier transfersAllowed {
assert(transfersEnabled);
_;
}
constructor() public {
setName("Evolution Land Global Token");
controller = msg.sender;
}
//////////
// IOwned Methods
//////////
/**
@dev allows transferring the contract ownership
the new owner still needs to accept the transfer
can only be called by the contract owner
@param _newOwner new contract owner
*/
function transferOwnership(address _newOwner) public auth {
require(_newOwner != owner);
newOwner = _newOwner;
}
/**
@dev used by a new owner to accept an ownership transfer
*/
function acceptOwnership() public {
require(msg.sender == newOwner);
owner = newOwner;
newOwner = address(0);
}
//////////
// SmartToken Methods
//////////
/**
@dev disables/enables transfers
can only be called by the contract owner
@param _disable true to disable transfers, false to enable them
*/
function disableTransfers(bool _disable) public auth {
transfersEnabled = !_disable;
}
function issue(address _to, uint256 _amount) public auth stoppable {
mint(_to, _amount);
}
function destroy(address _from, uint256 _amount) public auth stoppable {
// do not require allowance
_balances[_from] = sub(_balances[_from], _amount);
_supply = sub(_supply, _amount);
emit Burn(_from, _amount);
emit Transfer(_from, 0, _amount);
}
//////////
// Cap Methods
//////////
function changeCap(uint256 _newCap) public auth {
require(_newCap >= _supply);
cap = _newCap;
}
//////////
// Controller Methods
//////////
/// @notice Changes the controller of the contract
/// @param _newController The new controller of the contract
function changeController(address _newController) auth {
controller = _newController;
}
/// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
/// is approved by `_from`
/// @param _from The address holding the tokens being transferred
/// @param _to The address of the recipient
/// @param _amount The amount of tokens to be transferred
/// @return True if the transfer was successful
function transferFrom(address _from, address _to, uint256 _amount
) public transfersAllowed returns (bool success) {
// Alerts the token controller of the transfer
if (isContract(controller)) {
if (!TokenController(controller).onTransfer(_from, _to, _amount))
revert();
}
success = super.transferFrom(_from, _to, _amount);
}
/*
* ERC 223
* Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload.
*/
function transferFrom(address _from, address _to, uint256 _amount, bytes _data)
public transfersAllowed
returns (bool success)
{
// Alerts the token controller of the transfer
if (isContract(controller)) {
if (!TokenController(controller).onTransfer(_from, _to, _amount))
revert();
}
require(super.transferFrom(_from, _to, _amount));
if (isContract(_to)) {
ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
receiver.tokenFallback(_from, _amount, _data);
}
emit ERC223Transfer(_from, _to, _amount, _data);
return true;
}
/*
* ERC 223
* Added support for the ERC 223 "tokenFallback" method in a "transfer" function with a payload.
* https://github.com/ethereum/EIPs/issues/223
* function transfer(address _to, uint256 _value, bytes _data) public returns (bool success);
*/
/// @notice Send `_value` tokens to `_to` from `msg.sender` and trigger
/// tokenFallback if sender is a contract.
/// @dev Function that is called when a user or another contract wants to transfer funds.
/// @param _to Address of token receiver.
/// @param _amount Number of tokens to transfer.
/// @param _data Data to be sent to tokenFallback
/// @return Returns success of function call.
function transfer(
address _to,
uint256 _amount,
bytes _data)
public
returns (bool success)
{
return transferFrom(msg.sender, _to, _amount, _data);
}
/// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
/// its behalf. This is a modified version of the ERC20 approve function
/// to be a little bit safer
/// @param _spender The address of the account able to transfer the tokens
/// @param _amount The amount of tokens to be approved for transfer
/// @return True if the approval was successful
function approve(address _spender, uint256 _amount) returns (bool success) {
// Alerts the token controller of the approve function call
if (isContract(controller)) {
if (!TokenController(controller).onApprove(msg.sender, _spender, _amount))
revert();
}
return super.approve(_spender, _amount);
}
function mint(address _guy, uint _wad) auth stoppable {
require(add(_supply, _wad) <= cap);
super.mint(_guy, _wad);
emit Transfer(0, _guy, _wad);
}
function burn(address _guy, uint _wad) auth stoppable {
super.burn(_guy, _wad);
emit Transfer(_guy, 0, _wad);
}
/// @notice `msg.sender` approves `_spender` to send `_amount` tokens on
/// its behalf, and then a function is triggered in the contract that is
/// being approved, `_spender`. This allows users to use their tokens to
/// interact with contracts in one function call instead of two
/// @param _spender The address of the contract able to transfer the tokens
/// @param _amount The amount of tokens to be approved for transfer
/// @return True if the function call was successful
function approveAndCall(address _spender, uint256 _amount, bytes _extraData
) returns (bool success) {
if (!approve(_spender, _amount)) revert();
ApproveAndCallFallBack(_spender).receiveApproval(
msg.sender,
_amount,
this,
_extraData
);
return true;
}
/// @dev Internal function to determine if an address is a contract
/// @param _addr The address being queried
/// @return True if `_addr` is a contract
function isContract(address _addr) constant internal returns(bool) {
uint size;
if (_addr == 0) return false;
assembly {
size := extcodesize(_addr)
}
return size>0;
}
/// @notice The fallback function: If the contract's controller has not been
/// set to 0, then the `proxyPayment` method is called which relays the
/// ether and creates tokens as described in the token controller contract
function () payable {
if (isContract(controller)) {
if (! TokenController(controller).proxyPayment.value(msg.value)(msg.sender, msg.sig, msg.data))
revert();
} else {
revert();
}
}
//////////
// Safety Methods
//////////
/// @notice This method can be used by the owner to extract mistakenly
/// sent tokens to this contract.
/// @param _token The address of the token contract that you want to recover
/// set to 0 in case you want to extract ether.
function claimTokens(address _token) public auth {
if (_token == 0x0) {
address(msg.sender).transfer(address(this).balance);
return;
}
ERC20 token = ERC20(_token);
uint balance = token.balanceOf(this);
token.transfer(address(msg.sender), balance);
emit ClaimedTokens(_token, address(msg.sender), balance);
}
function withdrawTokens(ERC20 _token, address _to, uint256 _amount) public auth
{
assert(_token.transfer(_to, _amount));
}
////////////////
// Events
////////////////
event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount);
}
// File: contracts/interfaces/ISettingsRegistry.sol
pragma solidity ^0.4.24;
contract ISettingsRegistry {
enum SettingsValueTypes { NONE, UINT, STRING, ADDRESS, BYTES, BOOL, INT }
function uintOf(bytes32 _propertyName) public view returns (uint256);
function stringOf(bytes32 _propertyName) public view returns (string);
function addressOf(bytes32 _propertyName) public view returns (address);
function bytesOf(bytes32 _propertyName) public view returns (bytes);
function boolOf(bytes32 _propertyName) public view returns (bool);
function intOf(bytes32 _propertyName) public view returns (int);
function setUintProperty(bytes32 _propertyName, uint _value) public;
function setStringProperty(bytes32 _propertyName, string _value) public;
function setAddressProperty(bytes32 _propertyName, address _value) public;
function setBytesProperty(bytes32 _propertyName, bytes _value) public;
function setBoolProperty(bytes32 _propertyName, bool _value) public;
function setIntProperty(bytes32 _propertyName, int _value) public;
function getValueTypeOf(bytes32 _propertyName) public view returns (uint /* SettingsValueTypes */ );
event ChangeProperty(bytes32 indexed _propertyName, uint256 _type);
}
// File: contracts/interfaces/IAuthority.sol
pragma solidity ^0.4.24;
contract IAuthority {
function canCall(
address src, address dst, bytes4 sig
) public view returns (bool);
}
// File: contracts/DSAuth.sol
pragma solidity ^0.4.24;
contract DSAuthEvents {
event LogSetAuthority (address indexed authority);
event LogSetOwner (address indexed owner);
}
/**
* @title DSAuth
* @dev The DSAuth contract is reference implement of https://github.com/dapphub/ds-auth
* But in the isAuthorized method, the src from address(this) is remove for safty concern.
*/
contract DSAuth is DSAuthEvents {
IAuthority public authority;
address public owner;
constructor() public {
owner = msg.sender;
emit LogSetOwner(msg.sender);
}
function setOwner(address owner_)
public
auth
{
owner = owner_;
emit LogSetOwner(owner);
}
function setAuthority(IAuthority authority_)
public
auth
{
authority = authority_;
emit LogSetAuthority(authority);
}
modifier auth {
require(isAuthorized(msg.sender, msg.sig));
_;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
if (src == owner) {
return true;
} else if (authority == IAuthority(0)) {
return false;
} else {
return authority.canCall(src, this, sig);
}
}
}
// File: contracts/SettingsRegistry.sol
pragma solidity ^0.4.24;
/**
* @title SettingsRegistry
* @dev This contract holds all the settings for updating and querying.
*/
contract SettingsRegistry is ISettingsRegistry, DSAuth {
mapping(bytes32 => uint256) public uintProperties;
mapping(bytes32 => string) public stringProperties;
mapping(bytes32 => address) public addressProperties;
mapping(bytes32 => bytes) public bytesProperties;
mapping(bytes32 => bool) public boolProperties;
mapping(bytes32 => int256) public intProperties;
mapping(bytes32 => SettingsValueTypes) public valueTypes;
function uintOf(bytes32 _propertyName) public view returns (uint256) {
require(valueTypes[_propertyName] == SettingsValueTypes.UINT, "Property type does not match.");
return uintProperties[_propertyName];
}
function stringOf(bytes32 _propertyName) public view returns (string) {
require(valueTypes[_propertyName] == SettingsValueTypes.STRING, "Property type does not match.");
return stringProperties[_propertyName];
}
function addressOf(bytes32 _propertyName) public view returns (address) {
require(valueTypes[_propertyName] == SettingsValueTypes.ADDRESS, "Property type does not match.");
return addressProperties[_propertyName];
}
function bytesOf(bytes32 _propertyName) public view returns (bytes) {
require(valueTypes[_propertyName] == SettingsValueTypes.BYTES, "Property type does not match.");
return bytesProperties[_propertyName];
}
function boolOf(bytes32 _propertyName) public view returns (bool) {
require(valueTypes[_propertyName] == SettingsValueTypes.BOOL, "Property type does not match.");
return boolProperties[_propertyName];
}
function intOf(bytes32 _propertyName) public view returns (int) {
require(valueTypes[_propertyName] == SettingsValueTypes.INT, "Property type does not match.");
return intProperties[_propertyName];
}
function setUintProperty(bytes32 _propertyName, uint _value) public auth {
require(
valueTypes[_propertyName] == SettingsValueTypes.NONE || valueTypes[_propertyName] == SettingsValueTypes.UINT, "Property type does not match.");
uintProperties[_propertyName] = _value;
valueTypes[_propertyName] = SettingsValueTypes.UINT;
emit ChangeProperty(_propertyName, uint256(SettingsValueTypes.UINT));
}
function setStringProperty(bytes32 _propertyName, string _value) public auth {
require(
valueTypes[_propertyName] == SettingsValueTypes.NONE || valueTypes[_propertyName] == SettingsValueTypes.STRING, "Property type does not match.");
stringProperties[_propertyName] = _value;
valueTypes[_propertyName] = SettingsValueTypes.STRING;
emit ChangeProperty(_propertyName, uint256(SettingsValueTypes.STRING));
}
function setAddressProperty(bytes32 _propertyName, address _value) public auth {
require(
valueTypes[_propertyName] == SettingsValueTypes.NONE || valueTypes[_propertyName] == SettingsValueTypes.ADDRESS, "Property type does not match.");
addressProperties[_propertyName] = _value;
valueTypes[_propertyName] = SettingsValueTypes.ADDRESS;
emit ChangeProperty(_propertyName, uint256(SettingsValueTypes.ADDRESS));
}
function setBytesProperty(bytes32 _propertyName, bytes _value) public auth {
require(
valueTypes[_propertyName] == SettingsValueTypes.NONE || valueTypes[_propertyName] == SettingsValueTypes.BYTES, "Property type does not match.");
bytesProperties[_propertyName] = _value;
valueTypes[_propertyName] = SettingsValueTypes.BYTES;
emit ChangeProperty(_propertyName, uint256(SettingsValueTypes.BYTES));
}
function setBoolProperty(bytes32 _propertyName, bool _value) public auth {
require(
valueTypes[_propertyName] == SettingsValueTypes.NONE || valueTypes[_propertyName] == SettingsValueTypes.BOOL, "Property type does not match.");
boolProperties[_propertyName] = _value;
valueTypes[_propertyName] = SettingsValueTypes.BOOL;
emit ChangeProperty(_propertyName, uint256(SettingsValueTypes.BOOL));
}
function setIntProperty(bytes32 _propertyName, int _value) public auth {
require(
valueTypes[_propertyName] == SettingsValueTypes.NONE || valueTypes[_propertyName] == SettingsValueTypes.INT, "Property type does not match.");
intProperties[_propertyName] = _value;
valueTypes[_propertyName] = SettingsValueTypes.INT;
emit ChangeProperty(_propertyName, uint256(SettingsValueTypes.INT));
}
function getValueTypeOf(bytes32 _propertyName) public view returns (uint256 /* SettingsValueTypes */ ) {
return uint256(valueTypes[_propertyName]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment