ERC-20
Source Code
Overview
Max Total Supply
2,133 CW
Holders
2
Transfers
-
0
Market
Onchain Market Cap
-
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 0 Decimals)
Loading...
Loading
Loading...
Loading
Loading...
Loading
| # | Exchange | Pair | Price | 24H Volume | % Volume |
|---|
Contract Name:
CryptoWarriorCore
Compiler Version
v0.4.19+commit.c4cbbb05
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2018-02-27
*/
pragma solidity ^0.4.19;
contract ERC721 {
// Required methods
function totalSupply() public view returns (uint256 total);
function balanceOf(address _owner) public view returns (uint256 balance);
function ownerOf(uint256 _tokenId) external view returns (address owner);
function approve(address _to, uint256 _tokenId) external;
function transfer(address _to, uint256 _tokenId) external;
function transferFrom(address _from, address _to, uint256 _tokenId) external;
// Events
event Transfer(address from, address to, uint256 tokenId);
event Approval(address owner, address approved, uint256 tokenId);
function supportsInterface(bytes4 _interfaceID) external view returns (bool);
function getBeneficiary() external view returns(address);
}
contract GeneratorInterface {
function isGenerator() public pure returns (bool);
/// @dev generate new warrior genes
/// @param _heroGenes Genes of warrior that have completed dungeon
/// @param _heroLevel Level of the warrior
/// @return the genes that are supposed to be passed down to newly arisen warrior
function generateWarrior(uint256 _heroGenes, uint256 _heroLevel, uint256 _targetBlock, uint256 _perkId) public returns (uint256);
}
contract PVPInterface {
function isPVPProvider() external pure returns (bool);
function addTournamentContender(address _owner, uint256[] _tournamentData) external payable;
function getTournamentThresholdFee() public view returns(uint256);
function addPVPContender(address _owner, uint256 _packedWarrior) external payable;
function getPVPEntranceFee(uint256 _levelPoints) external view returns(uint256);
}
contract PVPListenerInterface {
function isPVPListener() public pure returns (bool);
function getBeneficiary() external view returns(address);
function pvpFinished(uint256[] warriorData, uint256 matchingCount) public;
function pvpContenderRemoved(uint32 _warriorId) public;
function tournamentFinished(uint256[] packedContenders) public;
}
// - The Admin: The Admin performs administrative functions, such as pause, unpause, change dependent contracts
// contracts.
//
// - The Bank: the beneficiary of all contracts
//
// - The Issuer: The Issuer can release miner warriors to auction.
contract PermissionControll {
event ContractUpgrade(address newContract);
address public newContractAddress;
address public adminAddress;
address public bankAddress;
address public issuerAddress;
bool public paused = false;
modifier onlyAdmin(){
require(msg.sender == adminAddress);
_;
}
modifier onlyBank(){
require(msg.sender == bankAddress);
_;
}
modifier onlyIssuer(){
require(msg.sender == issuerAddress);
_;
}
modifier onlyAuthorized(){
require(msg.sender == issuerAddress ||
msg.sender == adminAddress ||
msg.sender == bankAddress);
_;
}
function setBank(address _newBank) external onlyBank {
require(_newBank != address(0));
bankAddress = _newBank;
}
function setAdmin(address _newAdmin) external {
require(msg.sender == adminAddress || msg.sender == bankAddress);
require(_newAdmin != address(0));
adminAddress = _newAdmin;
}
function setIssuer(address _newIssuer) external onlyAdmin{
require(_newIssuer != address(0));
issuerAddress = _newIssuer;
}
modifier whenNotPaused(){
require(!paused);
_;
}
modifier whenPaused{
require(paused);
_;
}
function pause() external onlyAuthorized whenNotPaused{
paused = true;
}
function unpause() public onlyAdmin whenPaused{
paused = false;
}
function setNewAddress(address _v2Address) external onlyAdmin whenPaused {
newContractAddress = _v2Address;
ContractUpgrade(_v2Address);
}
}
contract Ownable {
address public owner;
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function Ownable() 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 transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner{
if (newOwner != address(0)) {
owner = newOwner;
}
}
}
contract Pausable is Ownable {
event Pause();
event Unpause();
bool public paused = false;
/**
* @dev modifier to allow actions only when the contract IS paused
*/
modifier whenNotPaused(){
require(!paused);
_;
}
/**
* @dev modifier to allow actions only when the contract IS NOT paused
*/
modifier whenPaused{
require(paused);
_;
}
/**
* @dev called by the owner to pause, triggers stopped state
*/
function pause() public onlyOwner whenNotPaused {
paused = true;
Pause();
}
/**
* @dev called by the owner to unpause, returns to normal state
*/
function unpause() public onlyOwner whenPaused {
paused = false;
Unpause();
}
}
library DataTypes {
struct Warrior{
// The Warrior's identity code is packed into these 256-bits
uint256 identity;
uint64 cooldownEndBlock;
/** every warriors starts from 1 lv (10 level points per level) */
uint64 level;
/** PVP rating, every warrior starts with 100 rating */
int64 rating;
// 0 - idle
uint32 action;
/** Set to the index in the levelRequirements array (see CryptoWarriorBase.levelRequirements) that represents
* the current dungeon level requirement for warrior. This starts at zero. */
uint32 dungeonIndex;
}
}
contract CryptoWarriorBase is PermissionControll, PVPListenerInterface {
/// @dev The Arise event is fired when a new warrior created.
event Arise(address owner, uint256 warriorId, uint256 identity);
/// @dev ERC721 Transfer event
event Transfer(address from, address to, uint256 tokenId);
/*** CONSTANTS ***/
uint256 public constant IDLE = 0;
uint256 public constant PVE_BATTLE = 1;
uint256 public constant PVP_BATTLE = 2;
uint256 public constant TOURNAMENT_BATTLE = 3;
//max pve dungeon level
uint256 public constant MAX_LEVEL = 25;
//how many points is needed to get 1 level
uint256 public constant POINTS_TO_LEVEL = 10;
/// @dev Array contains PVE dungeon level requirements, each time warrior
/// completes dungeon, next level requirement is set, until 25lv (250points) is reached.
uint32[6] public dungeonRequirements = [
uint32(10),
uint32(30),
uint32(60),
uint32(100),
uint32(150),
uint32(250)
];
uint256 public secondsPerBlock = 15;
/*** STORAGE ***/
/// @dev An array of warrior tokens
DataTypes.Warrior[] warriors;
/// @dev A mapping of warrior id to owner address
mapping (uint256 => address) public warriorToOwner;
// @dev A mapping from owner address to warriors count
mapping (address => uint256) ownersTokenCount;
/// @dev A mapping from warror id to approved address, that have permission to transfer specified warrior
mapping (uint256 => address) public warriorToApproved;
SaleClockAuction public saleAuction;
/// @dev Assigns ownership of a specific warrior to an address.
function _transfer(address _from, address _to, uint256 _tokenId) internal {
// Since the number of warriors is capped to '1 000 000' we can't overflow this
ownersTokenCount[_to]++;
// transfer ownership
warriorToOwner[_tokenId] = _to;
// When creating new warriors _from is 0x0, but we can't account that address.
if (_from != address(0)) {
ownersTokenCount[_from]--;
// clear any previously approved ownership exchange
delete warriorToApproved[_tokenId];
}
// Emit the transfer event.
Transfer(_from, _to, _tokenId);
}
/// @param _identity The warrior's genetic code.
/// @param _owner The initial owner of this warrior, must be non-zero
/// @param _cooldown pve cooldown block number
function _createWarrior(uint256 _identity, address _owner, uint256 _cooldown)
internal
returns (uint256) {
DataTypes.Warrior memory _warrior = DataTypes.Warrior({
identity : _identity,
cooldownEndBlock : uint64(_cooldown),
level : uint64(10),
rating : int64(100),
action : uint32(IDLE),
dungeonIndex : uint32(0)
});
uint256 newWarriorId = warriors.push(_warrior) - 1;
require(newWarriorId == uint256(uint32(newWarriorId)));
// emit the arise event
Arise(_owner, newWarriorId, _identity);
// emit the Transfer event
_transfer(0, _owner, newWarriorId);
return newWarriorId;
}
function setSecondsPerBlock(uint256 secs) external onlyAuthorized {
secondsPerBlock = secs;
}
}
contract WarriorTokenImpl is CryptoWarriorBase, ERC721 {
string public constant name = "CryptoWarriors";
string public constant symbol = "CW";
bytes4 constant InterfaceSignature_ERC165 =
bytes4(keccak256('supportsInterface(bytes4)'));
bytes4 constant InterfaceSignature_ERC721 =
bytes4(keccak256('name()')) ^
bytes4(keccak256('symbol()')) ^
bytes4(keccak256('totalSupply()')) ^
bytes4(keccak256('balanceOf(address)')) ^
bytes4(keccak256('ownerOf(uint256)')) ^
bytes4(keccak256('approve(address,uint256)')) ^
bytes4(keccak256('transfer(address,uint256)')) ^
bytes4(keccak256('transferFrom(address,address,uint256)')) ^
bytes4(keccak256('tokensOfOwner(address)'));
function supportsInterface(bytes4 _interfaceID) external view returns (bool)
{
return ((_interfaceID == InterfaceSignature_ERC165) || (_interfaceID == InterfaceSignature_ERC721));
}
function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {
return warriorToOwner[_tokenId] == _claimant;
}
function _ownerApproved(address _claimant, uint256 _tokenId) internal view returns (bool) {
return warriorToOwner[_tokenId] == _claimant && warriorToApproved[_tokenId] == address(0);
}
function _approvedFor(address _claimant, uint256 _tokenId) internal view returns (bool) {
return warriorToApproved[_tokenId] == _claimant;
}
function _approve(uint256 _tokenId, address _approved) internal {
warriorToApproved[_tokenId] = _approved;
}
/// @notice ERC-721 method.
function balanceOf(address _owner) public view returns (uint256 count) {
return ownersTokenCount[_owner];
}
/// @notice ERC-721 method.
function transfer(address _to, uint256 _tokenId) external whenNotPaused {
//sanity check
require(_to != address(0));
//can't transfer to core contract
require(_to != address(this));
//can't transfer to auction contract
require(_to != address(saleAuction));
// You can only send your own warrior.
require(_owns(msg.sender, _tokenId));
// Only idle warriors are allowed
require(warriors[_tokenId].action == IDLE);
// actually transfer warrior
_transfer(msg.sender, _to, _tokenId);
}
/// @notice ERC-721 method.
function approve(address _to, uint256 _tokenId) external whenNotPaused {
// Only owner can approve
require(_owns(msg.sender, _tokenId));
// Only idle warriors are allowed
require(warriors[_tokenId].action == IDLE);
// actually approve
_approve(_tokenId, _to);
// Emit event.
Approval(msg.sender, _to, _tokenId);
}
/// @notice ERC-721 method.
function transferFrom(address _from, address _to, uint256 _tokenId)
external
whenNotPaused
{
// Sanity check
require(_to != address(0));
// Disallow transfers to this contract to prevent accidental misuse.
// The contract should never own any warriors (except very briefly
// after a miner warrior is created and before it goes on auction).
require(_to != address(this));
// Check for approval and valid ownership
require(_approvedFor(msg.sender, _tokenId));
require(_owns(_from, _tokenId));
// Only idle warriors are allowed
require(warriors[_tokenId].action == IDLE);
// Reassign ownership (also clears pending approvals and emits Transfer event).
_transfer(_from, _to, _tokenId);
}
/// @notice ERC-721 method.
function totalSupply() public view returns (uint256) {
return warriors.length;
}
/// @notice ERC-721 method.
function ownerOf(uint256 _tokenId)
external
view
returns (address owner)
{
owner = warriorToOwner[_tokenId];
require(owner != address(0));
}
/// @notice ERC-721 method.
function tokensOfOwner(address _owner) external view returns(uint256[] ownerTokens) {
uint256 tokenCount = balanceOf(_owner);
if (tokenCount == 0) {
return new uint256[](0);
} else {
uint256[] memory result = new uint256[](tokenCount);
uint256 totalWarriors = totalSupply();
uint256 resultIndex = 0;
uint256 warriorId;
for (warriorId = 0; warriorId < totalWarriors; warriorId++) {
if (warriorToOwner[warriorId] == _owner) {
result[resultIndex] = warriorId;
resultIndex++;
}
}
return result;
}
}
}
contract CryptoWarriorPVE is WarriorTokenImpl {
uint256 internal constant SUMMONING_SICKENESS = 12;
uint256 internal constant PVE_COOLDOWN = 1 hours;
uint256 internal constant PVE_DURATION = 15 minutes;
/// @notice The payment required to use startPVEBattle().
uint256 public pveBattleFee = 10 finney;
uint256 public constant PVE_COMPENSATION = 2 finney;
/// @dev The address of contract that is used to implement warrior generation algorithm.
GeneratorInterface public generator;
/** @dev PVEStarted event. Emitted every time a warrior enters pve battle
* @param owner Warrior owner
* @param dungeonIndex Started dungeon index
* @param warriorId Warrior ID that started PVE dungeon
* @param battleEndBlock Block number, when started PVE dungeon will be completed
*/
event PVEStarted(address owner, uint256 dungeonIndex, uint256 warriorId, uint256 battleEndBlock);
/** @dev PVEFinished event. Emitted every time a warrior finishes pve battle
* @param owner Warrior owner
* @param dungeonIndex Finished dungeon index
* @param warriorId Warrior ID that completed dungeon
* @param cooldownEndBlock Block number, when cooldown on PVE battle entrance will be over
* @param rewardId Warrior ID which was granted to the owner as battle reward
*/
event PVEFinished(address owner, uint256 dungeonIndex, uint256 warriorId, uint256 cooldownEndBlock, uint256 rewardId);
/// @dev Update the address of the generator contract, can only be called by the Admin.
/// @param _address An address of a Generator contract instance to be used from this point forward.
function setGeneratorAddress(address _address) external onlyAdmin {
GeneratorInterface candidateContract = GeneratorInterface(_address);
// NOTE: verify that a contract is what we expect - https://github.com/Lunyr/crowdsale-contracts/blob/cfadd15986c30521d8ba7d5b6f57b4fefcc7ac38/contracts/LunyrToken.sol#L117
require(candidateContract.isGenerator());
// Set the new contract address
generator = candidateContract;
}
function areUnique(uint32[] memory _warriorIds) internal pure returns(bool) {
uint256 length = _warriorIds.length;
uint256 j;
for(uint256 i = 0; i < length; i++) {
for(j = i + 1; j < length; j++) {
if (_warriorIds[i] == _warriorIds[j]) return false;
}
}
return true;
}
/// @dev Updates the minimum payment required for calling startPVE(). Can only
/// be called by the admin address.
function setPVEBattleFee(uint256 _pveBattleFee) external onlyAdmin {
require(_pveBattleFee > PVE_COMPENSATION);
pveBattleFee = _pveBattleFee;
}
/** @dev Returns PVE cooldown, after each battle, the warrior receives a
* cooldown on the next entrance to the battle, cooldown depends on current warrior level,
* which is multiplied by 1h. Special case: after receiving 25 lv, the cooldwon will be 14 days.
* @param _levelPoints warrior level */
function getPVECooldown(uint256 _levelPoints) public pure returns (uint256) {
uint256 level = CryptoUtils._getLevel(_levelPoints);
if (level >= MAX_LEVEL) return (14 * 24 * PVE_COOLDOWN);//14 days
return (PVE_COOLDOWN * level);
}
/** @dev Returns PVE duration, each battle have a duration, which depends on current warrior level,
* which is multiplied by 15 min. At the end of the duration, warrior is becoming eligible to receive
* battle reward (new warrior in shiny armor)
* @param _levelPoints warrior level points
*/
function getPVEDuration(uint256 _levelPoints) public pure returns (uint256) {
return CryptoUtils._getLevel(_levelPoints) * PVE_DURATION;
}
/// @dev Checks that a given warrior can participate in PVE battle. Requires that the
/// current cooldown is finished and also checks that warrior is idle (does not participate in any action)
/// and dungeon level requirement is satisfied
function _isReadyToPVE(DataTypes.Warrior _warrior) internal view returns (bool) {
return (_warrior.action == IDLE) && //is idle
(_warrior.cooldownEndBlock <= uint64(block.number)) && //no cooldown
(_warrior.level >= dungeonRequirements[_warrior.dungeonIndex]);//dungeon level requirement is satisfied
}
/// @dev Internal utility function to initiate pve battle, assumes that all battle
/// requirements have been checked.
function _triggerPVEStart(uint256 _warriorId) internal {
// Grab a reference to the warrior from storage.
DataTypes.Warrior storage warrior = warriors[_warriorId];
// Set warrior current action to pve battle
warrior.action = uint16(PVE_BATTLE);
// Set battle duration
warrior.cooldownEndBlock = uint64((getPVEDuration(warrior.level) / secondsPerBlock) + block.number);
// Emit the pve battle start event.
PVEStarted(msg.sender, warrior.dungeonIndex, _warriorId, warrior.cooldownEndBlock);
}
/// @dev Starts PVE battle for specified warrior,
/// after battle, warrior owner will receive reward (Warrior)
/// @param _warriorId A Warrior ready to PVE battle.
function startPVE(uint256 _warriorId) external payable whenNotPaused {
// Checks for payment.
require(msg.value >= pveBattleFee);
// Caller must own the warrior.
require(_ownerApproved(msg.sender, _warriorId));
// Grab a reference to the warrior in storage.
DataTypes.Warrior storage warrior = warriors[_warriorId];
// Check that the warrior exists.
require(warrior.identity != 0);
// Check that the warrior is ready to battle
require(_isReadyToPVE(warrior));
// All checks passed, let the battle begin!
_triggerPVEStart(_warriorId);
// Calculate any excess funds included in msg.value. If the excess
// is anything worth worrying about, transfer it back to message owner.
// NOTE: We checked above that the msg.value is greater than or
// equal to the price so this cannot underflow.
uint256 feeExcess = msg.value - pveBattleFee;
// Return the funds. This is not susceptible
// to a re-entry attack because of _isReadyToPVE check
// will fail
msg.sender.transfer(feeExcess);
//send battle fee to beneficiary
bankAddress.transfer(pveBattleFee - PVE_COMPENSATION);
}
function _ariseWarrior(address _owner, DataTypes.Warrior storage _warrior) internal returns(uint256) {
uint256 identity = generator.generateWarrior(_warrior.identity, CryptoUtils._getLevel(_warrior.level), _warrior.cooldownEndBlock - 1, 0);
return _createWarrior(identity, _owner, block.number + (PVE_COOLDOWN * SUMMONING_SICKENESS / secondsPerBlock));
}
/// @dev Internal utility function to finish pve battle, assumes that all battle
/// finish requirements have been checked.
function _triggerPVEFinish(uint256 _warriorId) internal {
// Grab a reference to the warrior in storage.
DataTypes.Warrior storage warrior = warriors[_warriorId];
// Set warrior current action to idle
warrior.action = uint16(IDLE);
// Compute an estimation of the cooldown time in blocks (based on current level).
// and miner perc also reduces cooldown time by 4 times
warrior.cooldownEndBlock = uint64((getPVECooldown(warrior.level) /
CryptoUtils._getBonus(warrior.identity) / secondsPerBlock) + block.number);
// cash completed dungeon index before increment
uint32 dungeonIndex = warrior.dungeonIndex;
// Increment the dungeon index, clamping it at 6, which is the length of the
// dungeonRequirements array. We could check the array size dynamically, but hard-coding
// this as a constant saves gas.
if (dungeonIndex < 6) {
warrior.dungeonIndex += 1;
}
address owner = warriorToOwner[_warriorId];
// generate reward
uint256 arisenWarriorId = _ariseWarrior(owner, warrior);
//Emit event
PVEFinished(owner, dungeonIndex, _warriorId, warrior.cooldownEndBlock, arisenWarriorId);
}
/**
* @dev finishPVE can be called after battle time is over,
* if checks are passed then battle result is computed,
* and new warrior is awarded to owner of specified _warriord ID.
* NB anyone can call this method, if they willing to pay the gas price
*/
function finishPVE(uint32 _warriorId) external whenNotPaused {
// Grab a reference to the warrior in storage.
DataTypes.Warrior storage warrior = warriors[_warriorId];
// Check that the warrior exists.
require(warrior.identity != 0);
// Check that warrior participated in PVE battle action
require(warrior.action == PVE_BATTLE);
// And the battle time is over
require(warrior.cooldownEndBlock <= uint64(block.number));
// When the all checks done, calculate actual battle result
_triggerPVEFinish(_warriorId);
//not susceptible to reetrance attack because of require(warrior.action == PVE_BATTLE)
//and require(warrior.cooldownEndBlock <= uint64(block.number));
msg.sender.transfer(PVE_COMPENSATION);
}
/**
* @dev finishPVEBatch same as finishPVE but for multiple warrior ids.
* NB anyone can call this method, if they willing to pay the gas price
*/
function finishPVEBatch(uint32[] _warriorIds) external whenNotPaused {
uint256 length = _warriorIds.length;
//check max number of bach finish pve
require(length <= 20);
uint256 blockNumber = block.number;
uint256 index;
//all warrior ids must be unique
require(areUnique(_warriorIds));
//check prerequisites
for(index = 0; index < length; index ++) {
DataTypes.Warrior storage warrior = warriors[_warriorIds[index]];
require(
// Check that the warrior exists.
warrior.identity != 0 &&
// Check that warrior participated in PVE battle action
warrior.action == PVE_BATTLE &&
// And the battle time is over
warrior.cooldownEndBlock <= blockNumber
);
}
// When the all checks done, calculate actual battle result
for(index = 0; index < length; index ++) {
_triggerPVEFinish(_warriorIds[index]);
}
//not susceptible to reetrance attack because of require(warrior.action == PVE_BATTLE)
//and require(warrior.cooldownEndBlock <= uint64(block.number));
msg.sender.transfer(PVE_COMPENSATION * length);
}
}
contract CryptoWarriorPVP is CryptoWarriorPVE {
PVPInterface public battleProvider;
/// @dev Sets the reference to the sale auction.
/// @param _address - Address of sale contract.
function setBattleProviderAddress(address _address) external onlyAdmin {
PVPInterface candidateContract = PVPInterface(_address);
// NOTE: verify that a contract is what we expect - https://github.com/Lunyr/crowdsale-contracts/blob/cfadd15986c30521d8ba7d5b6f57b4fefcc7ac38/contracts/LunyrToken.sol#L117
require(candidateContract.isPVPProvider());
// Set the new contract address
battleProvider = candidateContract;
}
function _packPVPData(uint256 _warriorId, DataTypes.Warrior storage warrior) internal view returns(uint256){
return CryptoUtils._packWarriorPvpData(warrior.identity, uint256(warrior.rating), 0, _warriorId, warrior.level);
}
function _triggerPVPSignUp(uint32 _warriorId, uint256 fee) internal {
DataTypes.Warrior storage warrior = warriors[_warriorId];
uint256 packedWarrior = _packPVPData(_warriorId, warrior);
// addPVPContender will throw if fee fails.
battleProvider.addPVPContender.value(fee)(msg.sender, packedWarrior);
warrior.action = uint16(PVP_BATTLE);
}
/*
* @title signUpForPVP enqueues specified warrior to PVP
*
* @dev When the owner enqueues his warrior for PvP, the warrior enters the waiting room.
* Once every 15 minutes, we check the warriors in the room and select pairs.
* For those warriors to whom we found couples, fighting is conducted and the results
* are recorded in the profile of the warrior.
*/
function signUpForPVP(uint32 _warriorId) public payable whenNotPaused {//done
// Caller must own the warrior.
require(_ownerApproved(msg.sender, _warriorId));
// Grab a reference to the warrior in storage.
DataTypes.Warrior storage warrior = warriors[_warriorId];
// sanity check
require(warrior.identity != 0);
// Check that the warrior is ready to battle
require(warrior.action == IDLE);
// Define the current price of the auction.
uint256 fee = battleProvider.getPVPEntranceFee(warrior.level);
// Checks for payment.
require(msg.value >= fee);
// All checks passed, put the warrior to the queue!
_triggerPVPSignUp(_warriorId, fee);
// Calculate any excess funds included in msg.value. If the excess
// is anything worth worrying about, transfer it back to message owner.
// NOTE: We checked above that the msg.value is greater than or
// equal to the price so this cannot underflow.
uint256 feeExcess = msg.value - fee;
// Return the funds. This is not susceptible
// to a re-entry attack because of warrior.action == IDLE check
// will fail
msg.sender.transfer(feeExcess);
}
function _grandPVPWinnerReward(uint256 _warriorId) internal {
DataTypes.Warrior storage warrior = warriors[_warriorId];
// reward 1 level, add 10 level points
uint256 level = warrior.level;
if (level < (MAX_LEVEL * POINTS_TO_LEVEL)) {
level = level + POINTS_TO_LEVEL;
warrior.level = uint64(level > (MAX_LEVEL * POINTS_TO_LEVEL) ? (MAX_LEVEL * POINTS_TO_LEVEL) : level);
}
// give 100 rating for levelUp and 30 for win
warrior.rating += 130;
// mark warrior idle, so it can participate
// in another actions
warrior.action = uint16(IDLE);
}
function _grandPVPLoserReward(uint256 _warriorId) internal {
DataTypes.Warrior storage warrior = warriors[_warriorId];
// reward 0.5 level
uint256 oldLevel = warrior.level;
uint256 level = oldLevel;
if (level < (MAX_LEVEL * POINTS_TO_LEVEL)) {
level += (POINTS_TO_LEVEL / 2);
warrior.level = uint64(level);
}
// give 100 rating for levelUp if happens and -30 for lose
int256 newRating = warrior.rating + (CryptoUtils._getLevel(level) > CryptoUtils._getLevel(oldLevel) ? int256(100 - 30) : int256(-30));
// rating can't be less than 0 and more than 1000000000
warrior.rating = int64((newRating >= 0) ? (newRating > 1000000000 ? 1000000000 : newRating) : 0);
// mark warrior idle, so it can participate
// in another actions
warrior.action = uint16(IDLE);
}
function _grandPVPRewards(uint256[] memory warriorsData, uint256 matchingCount) internal {
for(uint256 id = 0; id < matchingCount; id += 2){
//
// winner, even ids are winners!
_grandPVPWinnerReward(CryptoUtils._unpackIdValue(warriorsData[id]));
//
// loser, they are odd...
_grandPVPLoserReward(CryptoUtils._unpackIdValue(warriorsData[id + 1]));
}
}
// @dev Internal utility function to initiate pvp battle, assumes that all battle
/// requirements have been checked.
function pvpFinished(uint256[] warriorsData, uint256 matchingCount) public {
//this method can be invoked only by battleProvider contract
require(msg.sender == address(battleProvider));
_grandPVPRewards(warriorsData, matchingCount);
}
function pvpContenderRemoved(uint32 _warriorId) public {
//this method can be invoked only by battleProvider contract
require(msg.sender == address(battleProvider));
//grab warrior storage reference
DataTypes.Warrior storage warrior = warriors[_warriorId];
//specified warrior must be in pvp state
require(warrior.action == PVP_BATTLE);
//all checks done
//set warrior state to IDLE
warrior.action = uint16(IDLE);
}
}
contract CryptoWarriorTournament is CryptoWarriorPVP {
uint256 internal constant GROUP_SIZE = 5;
function _ownsAll(address _claimant, uint32[] memory _warriorIds) internal view returns (bool) {
uint256 length = _warriorIds.length;
for(uint256 i = 0; i < length; i++) {
if (!_ownerApproved(_claimant, _warriorIds[i])) return false;
}
return true;
}
function _isReadyToTournament(DataTypes.Warrior storage _warrior) internal view returns(bool){
return _warrior.level >= 50 && _warrior.action == IDLE;//must not participate in any action
}
function _packTournamentData(uint32[] memory _warriorIds) internal view returns(uint256[] memory tournamentData) {
tournamentData = new uint256[](GROUP_SIZE);
uint256 warriorId;
for(uint256 i = 0; i < GROUP_SIZE; i++) {
warriorId = _warriorIds[i];
tournamentData[i] = _packPVPData(warriorId, warriors[warriorId]);
}
return tournamentData;
}
// @dev Internal utility function to sign up to tournament,
// assumes that all battle requirements have been checked.
function _triggerTournamentSignUp(uint32[] memory _warriorIds, uint256 fee) internal {
//pack warrior ids into into uint256
uint256[] memory tournamentData = _packTournamentData(_warriorIds);
for(uint256 i = 0; i < GROUP_SIZE; i++) {
// Set warrior current action to tournament battle
warriors[_warriorIds[i]].action = uint16(TOURNAMENT_BATTLE);
}
battleProvider.addTournamentContender.value(fee)(msg.sender, tournamentData);
}
function signUpForTournament(uint32[] _warriorIds) public payable {
//
//check that there is enough funds to pay entrance fee
uint256 fee = battleProvider.getTournamentThresholdFee();
require(msg.value >= fee);
//
//check that warriors group is exactly of allowed size
require(_warriorIds.length == GROUP_SIZE);
//
//message sender must own all the specified warrior IDs
require(_ownsAll(msg.sender, _warriorIds));
//
//check all warriors are unique
require(areUnique(_warriorIds));
//
//check that all warriors are 25 lv and IDLE
for(uint256 i = 0; i < GROUP_SIZE; i ++) {
// Grab a reference to the warrior in storage.
require(_isReadyToTournament(warriors[_warriorIds[i]]));
}
//all checks passed, trigger sign up
_triggerTournamentSignUp(_warriorIds, fee);
// Calculate any excess funds included in msg.value. If the excess
// is anything worth worrying about, transfer it back to message owner.
// NOTE: We checked above that the msg.value is greater than or
// equal to the fee so this cannot underflow.
uint256 feeExcess = msg.value - fee;
// Return the funds. This is not susceptible
// to a re-entry attack because of _isReadyToTournament check
// will fail
msg.sender.transfer(feeExcess);
}
function _setIDLE(uint256 warriorIds) internal {
for(uint256 i = 0; i < GROUP_SIZE; i ++) {
warriors[CryptoUtils._unpackWarriorId(warriorIds, i)].action = uint16(IDLE);
}
}
function _freeWarriors(uint256[] memory packedContenders) internal {
uint256 length = packedContenders.length;
for(uint256 i = 0; i < length; i ++) {
//set participants action to IDLE
_setIDLE(packedContenders[i]);
}
}
function tournamentFinished(uint256[] packedContenders) public {
//this method can be invoked only by battleProvider contract
require(msg.sender == address(battleProvider));
//grad rewards and set IDLE action
_freeWarriors(packedContenders);
}
}
contract CryptoWarriorAuction is CryptoWarriorTournament {
function setSaleAuctionAddress(address _address) external onlyAdmin {
SaleClockAuction candidateContract = SaleClockAuction(_address);
require(candidateContract.isSaleClockAuction());
saleAuction = candidateContract;
}
function createSaleAuction(
uint256 _warriorId,
uint256 _startingPrice,
uint256 _endingPrice,
uint256 _duration
)
external
whenNotPaused
{
// only owned and not approved to transfer warriors allowed
require(_ownerApproved(msg.sender, _warriorId));
// Ensure the warrior is not busy to prevent the auction
// contract creation while warrior is in any kind of battle (PVE, PVP, TOURNAMENT).
require(warriors[_warriorId].action == IDLE);
_approve(_warriorId, address(saleAuction));
// Actually create auction
saleAuction.createAuction(
_warriorId,
_startingPrice,
_endingPrice,
_duration,
msg.sender
);
}
}
contract CryptoWarriorIssuer is CryptoWarriorAuction {
// Limits the number of warriors the contract owner can ever create
uint256 public constant MINER_CREATION_LIMIT = 2880;//issue every 15min for one month
uint256 internal constant MINER_PERK = 1;
// Constants for miner auctions.
uint256 public constant MINER_STARTING_PRICE = 100 finney;
uint256 public constant MINER_END_PRICE = 50 finney;
uint256 public constant MINER_AUCTION_DURATION = 1 days;
uint256 public minerCreatedCount;
/// @dev Generates a new miner warrior with MINER perk of COMMON rarity
/// creates an auction for it.
function createMinerAuction() external onlyIssuer {
require(minerCreatedCount < MINER_CREATION_LIMIT);
minerCreatedCount++;
uint256 identity = generator.generateWarrior(minerCreatedCount, 0, block.number - 1, MINER_PERK);
uint256 warriorId = _createWarrior(identity, bankAddress, 0);
_approve(warriorId, address(saleAuction));
saleAuction.createAuction(
warriorId,
_computeNextMinerPrice(),
MINER_END_PRICE,
MINER_AUCTION_DURATION,
bankAddress
);
}
function _computeNextMinerPrice() internal view returns (uint256) {
uint256 avePrice = saleAuction.averageMinerSalePrice();
require(avePrice == uint256(uint128(avePrice)));
uint256 nextPrice = avePrice * 3 / 2;//confirmed
if (nextPrice < MINER_STARTING_PRICE) {
nextPrice = MINER_STARTING_PRICE;
}
return nextPrice;
}
}
contract CryptoWarriorCore is CryptoWarriorIssuer {
function CryptoWarriorCore() public {
// Starts paused.
paused = true;
// the creator of the contract is the initial Admin
adminAddress = msg.sender;
// the creator of the contract is also the initial Issuer
issuerAddress = msg.sender;
// the creator of the contract is also the initial Bank
bankAddress = msg.sender;
}
function() external payable {
require(false);
}
function unpause() public onlyAdmin whenPaused {
require(address(saleAuction) != address(0));
require(address(generator) != address(0));
require(address(battleProvider) != address(0));
require(newContractAddress == address(0));
// Actually unpause the contract.
super.unpause();
}
function getBeneficiary() external view returns(address) {
return bankAddress;
}
function isPVPListener() public pure returns (bool) {
return true;
}
/**
*@param _warriorIds array of warriorIds,
* for those IDs warrior data will be packed into warriorsData array
*@return warriorsData packed warrior data
*@return stepSize number of fields in single warrior data */
function getWarriors(uint32[] _warriorIds) external view returns (uint256[] memory warriorsData, uint32 stepSize) {
stepSize = 6;
warriorsData = new uint256[](_warriorIds.length * stepSize);
for(uint32 i = 0; i < _warriorIds.length; i++) {
_setWarriorData(warriorsData, warriors[_warriorIds[i]], i * stepSize);
}
}
/**
*@param indexFrom index in global warrior storage (aka warriorId),
* from this index(including), warriors data will be gathered
*@param count Number of warriors to include in packed data
*@return warriorsData packed warrior data
*@return stepSize number of fields in single warrior data */
function getWarriorsFromIndex(uint32 indexFrom, uint32 count) external view returns (uint256[] memory warriorsData, uint32 stepSize) {
stepSize = 6;
//check length
uint256 lenght = (warriors.length - indexFrom >= count ? count : warriors.length - indexFrom);
warriorsData = new uint256[](lenght * stepSize);
for(uint32 i = 0; i < lenght; i ++) {
_setWarriorData(warriorsData, warriors[indexFrom + i], i * stepSize);
}
}
function getWarriorOwners(uint32[] _warriorIds) external view returns (address[] memory owners) {
uint256 lenght = _warriorIds.length;
owners = new address[](lenght);
for(uint256 i = 0; i < lenght; i ++) {
owners[i] = warriorToOwner[_warriorIds[i]];
}
}
function _setWarriorData(uint256[] memory warriorsData, DataTypes.Warrior storage warrior, uint32 id) internal view {
warriorsData[id] = uint256(warrior.identity);//0
warriorsData[id + 1] = uint256(warrior.cooldownEndBlock);//1
warriorsData[id + 2] = uint256(warrior.level);//2
warriorsData[id + 3] = uint256(warrior.rating);//3
warriorsData[id + 4] = uint256(warrior.action);//4
warriorsData[id + 5] = uint256(warrior.dungeonIndex);//5
}
function getWarrior(uint256 _id) external view returns
(
uint256 identity,
uint256 cooldownEndBlock,
uint256 level,
uint256 rating,
uint256 action,
uint256 dungeonIndex
) {
DataTypes.Warrior storage warrior = warriors[_id];
identity = uint256(warrior.identity);
cooldownEndBlock = uint256(warrior.cooldownEndBlock);
level = uint256(warrior.level);
rating = uint256(warrior.rating);
action = uint256(warrior.action);
dungeonIndex = uint256(warrior.dungeonIndex);
}
}
contract PVP is Pausable, PVPInterface {
/* PVP BATLE */
/** list of packed warrior data that will participate in next PVP session.
* Fixed size arry, to evade constant remove and push operations,
* this approach reduces transaction costs involving queue modification. */
uint256[100] public pvpQueue;
//
//queue size
uint256 public pvpQueueSize = 0;
// @dev A mapping from owner address to booty in WEI
// booty is acquired in PVP and Tournament battles and can be
// withdrawn with grabBooty method by the owner of the loot
mapping (address => uint256) public ownerToBooty;
// @dev A mapping from warrior id to owners address
mapping (uint256 => address) internal warriorToOwner;
// An approximation of currently how many seconds are in between blocks.
uint256 internal secondsPerBlock = 15;
// Cut owner takes from, measured in basis points (1/100 of a percent).
// Values 0-10,000 map to 0%-100%
uint256 public pvpOwnerCut;
// Values 0-10,000 map to 0%-100%
//this % of the total bets will be sent as
//a reward to address, that triggered finishPVP method
uint256 public pvpMaxIncentiveCut;
/// @notice The payment base required to use startPVP().
// pvpBattleFee * (warrior.level / POINTS_TO_LEVEL)
uint256 internal pvpBattleFee = 20 finney;
uint256 public constant PVP_INTERVAL = 15 minutes;
uint256 public nextPVPBatleBlock = 0;
//number of WEI in hands of warrior owners
uint256 public totalBooty = 0;
/* TOURNAMENT */
uint256 public constant FUND_GATHERING_TIME = 24 hours;
uint256 public constant ADMISSION_TIME = 12 hours;
uint256 public constant RATING_EXPAND_INTERVAL = 1 hours;
uint256 internal constant SAFETY_GAP = 5;
uint256 internal constant MAX_INCENTIVE_REWARD = 200 finney;
//tournamentContenders size
uint256 public tournamentQueueSize = 0;
// Values 0-10,000 map to 0%-100%
uint256 public tournamentBankCut;
/** tournamentEndBlock, tournament is eligible to be finished only
* after block.number >= tournamentEndBlock
* it depends on FUND_GATHERING_TIME and ADMISSION_TIME */
uint256 public tournamentEndBlock;
//number of WEI in tournament bank
uint256 public currentTournamentBank = 0;
uint256 public nextTournamentBank = 0;
PVPListenerInterface internal pvpListener;
/* EVENTS */
/** @dev TournamentScheduled event. Emitted every time a tournament is scheduled
* @param tournamentEndBlock when block.number > tournamentEndBlock, then tournament
* is eligible to be finished or rescheduled */
event TournamentScheduled(uint256 tournamentEndBlock);
/** @dev PVPScheduled event. Emitted every time a tournament is scheduled
* @param nextPVPBatleBlock when block.number > nextPVPBatleBlock, then pvp battle
* is eligible to be finished or rescheduled */
event PVPScheduled(uint256 nextPVPBatleBlock);
/** @dev PVPNewContender event. Emitted every time a warrior enqueues pvp battle
* @param owner Warrior owner
* @param warriorId Warrior ID that entered PVP queue
* @param entranceFee fee in WEI warrior owner payed to enter PVP
*/
event PVPNewContender(address owner, uint256 warriorId, uint256 entranceFee);
/** @dev PVPFinished event. Emitted every time a pvp battle is finished
* @param warriorsData array of pairs of pvp warriors packed to uint256, even => winners, odd => losers
* @param owners array of warrior owners, 1 to 1 with warriorsData, even => winners, odd => losers
* @param matchingCount total number of warriors that fought in current pvp session and got rewards,
* if matchingCount < participants.length then all IDs that are >= matchingCount will
* remain in waiting room, until they are matched.
*/
event PVPFinished(uint256[] warriorsData, address[] owners, uint256 matchingCount);
/** @dev BootySendFailed event. Emitted every time address.send() function failed to transfer Ether to recipient
* in this case recipient Ether is recorded to ownerToBooty mapping, so recipient can withdraw their booty manually
* @param recipient address for whom send failed
* @param amount number of WEI we failed to send
*/
event BootySendFailed(address recipient, uint256 amount);
/** @dev BootyGrabbed event
* @param receiver address who grabbed his booty
* @param amount number of WEI
*/
event BootyGrabbed(address receiver, uint256 amount);
/** @dev PVPContenderRemoved event. Emitted every time warrior is removed from pvp queue by its owner.
* @param warriorId id of the removed warrior
*/
event PVPContenderRemoved(uint256 warriorId, address owner);
function PVP(uint256 _pvpCut, uint256 _tournamentBankCut, uint256 _pvpMaxIncentiveCut) public {
require((_tournamentBankCut + _pvpCut + _pvpMaxIncentiveCut) <= 10000);
pvpOwnerCut = _pvpCut;
tournamentBankCut = _tournamentBankCut;
pvpMaxIncentiveCut = _pvpMaxIncentiveCut;
}
/** @dev grabBooty sends to message sender his booty in WEI
*/
function grabBooty() external {
uint256 booty = ownerToBooty[msg.sender];
require(booty > 0);
require(totalBooty >= booty);
ownerToBooty[msg.sender] = 0;
totalBooty -= booty;
msg.sender.transfer(booty);
//emit event
BootyGrabbed(msg.sender, booty);
}
function safeSend(address _recipient, uint256 _amaunt) internal {
uint256 failedBooty = sendBooty(_recipient, _amaunt);
if (failedBooty > 0) {
totalBooty += failedBooty;
}
}
function sendBooty(address _recipient, uint256 _amaunt) internal returns(uint256) {
bool success = _recipient.send(_amaunt);
if (!success && _amaunt > 0) {
ownerToBooty[_recipient] += _amaunt;
BootySendFailed(_recipient, _amaunt);
return _amaunt;
}
return 0;
}
//@returns block number, after this block tournament is opened for admission
function getTournamentAdmissionBlock() public view returns(uint256) {
uint256 admissionInterval = (ADMISSION_TIME / secondsPerBlock);
return tournamentEndBlock < admissionInterval ? 0 : tournamentEndBlock - admissionInterval;
}
//schedules next turnament time(block)
function _scheduleTournament() internal {
//we can chedule only if there is nobody in tournament queue and
//time of tournament battle have passed
if (tournamentQueueSize == 0 && tournamentEndBlock <= block.number) {
tournamentEndBlock = ((FUND_GATHERING_TIME / 2 + ADMISSION_TIME) / secondsPerBlock) + block.number;
TournamentScheduled(tournamentEndBlock);
}
}
/// @dev Updates the minimum payment required for calling startPVP(). Can only
/// be called by the Owner address, and only if pvp queue is empty.
function setPVPEntranceFee(uint256 value) external onlyOwner {
require(pvpQueueSize == 0);
pvpBattleFee = value;
}
//@returns PVP entrance fee for specified warrior level
//@param _levelPoints NB!
function getPVPEntranceFee(uint256 _levelPoints) external view returns(uint256) {
return pvpBattleFee * CryptoUtils._getLevel(_levelPoints);
}
//level can only be > 0 and <= 25
function _getPVPFeeByLevel(uint256 _level) internal view returns(uint256) {
return pvpBattleFee * _level;
}
// @dev Computes warrior pvp reward
// @param _totalBet - total bet from both competitors.
function _computePVPReward(uint256 _totalBet, uint256 _contendersCut) internal pure returns (uint256){
// NOTE: We don't use SafeMath (or similar) in this function because
// _totalBet max value is 1000 finney, and _contendersCut aka
// (10000 - pvpOwnerCut - tournamentBankCut - incentiveRewardCut) <= 10000 (see the require()
// statement in the BattleProvider constructor). The result of this
// function is always guaranteed to be <= _totalBet.
return _totalBet * _contendersCut / 10000;
}
function _getPVPContendersCut(uint256 _incentiveCut) internal view returns (uint256) {
// NOTE: We don't use SafeMath (or similar) in this function because
// (pvpOwnerCut + tournamentBankCut + pvpMaxIncentiveCut) <= 10000 (see the require()
// statement in the BattleProvider constructor).
// _incentiveCut is guaranteed to be >= 1 and <= pvpMaxIncentiveCut
return (10000 - pvpOwnerCut - tournamentBankCut - _incentiveCut);
}
// @dev Computes warrior pvp reward
// @param _totalSessionLoot - total bets from all competitors.
function _computeIncentiveReward(uint256 _totalSessionLoot, uint256 _incentiveCut) internal pure returns (uint256){
// NOTE: We don't use SafeMath (or similar) in this function because
// _totalSessionLoot max value is 37500 finney, and
// (pvpOwnerCut + tournamentBankCut + incentiveRewardCut) <= 10000 (see the require()
// statement in the BattleProvider constructor). The result of this
// function is always guaranteed to be <= _totalSessionLoot.
return _totalSessionLoot * _incentiveCut / 10000;
}
///@dev computes incentive cut for specified loot,
/// Values 0-10,000 map to 0%-100%
/// max incentive reward cut is 5%, if it exceeds MAX_INCENTIVE_REWARD,
/// then cut is lowered to be equal to MAX_INCENTIVE_REWARD.
/// minimum cut is 0.01%
/// this % of the total bets will be sent as
/// a reward to address, that triggered finishPVP method
function _computeIncentiveCut(uint256 _totalSessionLoot, uint256 maxIncentiveCut) internal pure returns(uint256) {
uint256 result = _totalSessionLoot * maxIncentiveCut / 10000;
result = result <= MAX_INCENTIVE_REWARD ? maxIncentiveCut : MAX_INCENTIVE_REWARD * 10000 / _totalSessionLoot;
//min cut is 0.01%
return result > 0 ? result : 1;
}
// @dev Computes warrior pvp reward
// @param _totalSessionLoot - total bets from all competitors.
function _computePVPBeneficiaryFee(uint256 _totalSessionLoot) internal view returns (uint256){
// NOTE: We don't use SafeMath (or similar) in this function because
// _totalSessionLoot max value is 37500 finney, and
// (pvpOwnerCut + tournamentBankCut + incentiveRewardCut) <= 10000 (see the require()
// statement in the BattleProvider constructor). The result of this
// function is always guaranteed to be <= _totalSessionLoot.
return _totalSessionLoot * pvpOwnerCut / 10000;
}
// @dev Computes tournament bank cut
// @param _totalSessionLoot - total session loot.
function _computeTournamentCut(uint256 _totalSessionLoot) internal view returns (uint256){
// NOTE: We don't use SafeMath (or similar) in this function because
// _totalSessionLoot max value is 37500 finney, and
// (pvpOwnerCut + tournamentBankCut + incentiveRewardCut) <= 10000 (see the require()
// statement in the BattleProvider constructor). The result of this
// function is always guaranteed to be <= _totalSessionLoot.
return _totalSessionLoot * tournamentBankCut / 10000;
}
function indexOf(uint256 _warriorId) internal view returns(int256) {
uint256 length = uint256(pvpQueueSize);
for(uint256 i = 0; i < length; i ++) {
if(CryptoUtils._unpackIdValue(pvpQueue[i]) == _warriorId) return int256(i);
}
return -1;
}
function getPVPIncentiveReward(uint256[] memory matchingIds, uint256 matchingCount) internal view returns(uint256) {
uint256 sessionLoot = _computeTotalBooty(matchingIds, matchingCount);
return _computeIncentiveReward(sessionLoot, _computeIncentiveCut(sessionLoot, pvpMaxIncentiveCut));
}
function maxPVPContenders() external view returns(uint256){
return pvpQueue.length;
}
function getPVPState() external view returns
(uint256 contendersCount, uint256 matchingCount, uint256 endBlock, uint256 incentiveReward)
{
uint256[] memory pvpData = _packPVPData();
contendersCount = pvpQueueSize;
matchingCount = CryptoUtils._getMatchingIds(pvpData, PVP_INTERVAL, _computeCycleSkip(), RATING_EXPAND_INTERVAL);
endBlock = nextPVPBatleBlock;
incentiveReward = getPVPIncentiveReward(pvpData, matchingCount);
}
function canFinishPVP() external view returns(bool) {
return nextPVPBatleBlock <= block.number &&
CryptoUtils._getMatchingIds(_packPVPData(), PVP_INTERVAL, _computeCycleSkip(), RATING_EXPAND_INTERVAL) > 1;
}
function _clarifyPVPSchedule() internal {
uint256 length = pvpQueueSize;
uint256 currentBlock = block.number;
uint256 nextBattleBlock = nextPVPBatleBlock;
//if battle not scheduled, schedule battle
if (nextBattleBlock <= currentBlock) {
//if queue not empty update cycles
if (length > 0) {
uint256 packedWarrior;
uint256 cycleSkip = _computeCycleSkip();
for(uint256 i = 0; i < length; i++) {
packedWarrior = pvpQueue[i];
//increase warrior iteration cycle
pvpQueue[i] = CryptoUtils._changeCycleValue(packedWarrior, CryptoUtils._unpackCycleValue(packedWarrior) + cycleSkip);
}
}
nextBattleBlock = (PVP_INTERVAL / secondsPerBlock) + currentBlock;
nextPVPBatleBlock = nextBattleBlock;
PVPScheduled(nextBattleBlock);
//if pvp queue will be full and there is still too much time left, then let the battle begin!
} else if (length + 1 == pvpQueue.length && (currentBlock + SAFETY_GAP * 2) < nextBattleBlock) {
nextBattleBlock = currentBlock + SAFETY_GAP;
nextPVPBatleBlock = nextBattleBlock;
PVPScheduled(nextBattleBlock);
}
}
/// @dev Internal utility function to initiate pvp battle, assumes that all battle
/// requirements have been checked.
function _triggerNewPVPContender(address _owner, uint256 _packedWarrior, uint256 fee) internal {
_clarifyPVPSchedule();
//number of pvp cycles the warrior is waiting for suitable enemy match
//increment every time when finishPVP is called and no suitable enemy match was found
_packedWarrior = CryptoUtils._changeCycleValue(_packedWarrior, 0);
//record contender data
pvpQueue[pvpQueueSize++] = _packedWarrior;
warriorToOwner[CryptoUtils._unpackIdValue(_packedWarrior)] = _owner;
//Emit event
PVPNewContender(_owner, CryptoUtils._unpackIdValue(_packedWarrior), fee);
}
function _noMatchingPairs() internal view returns(bool) {
uint256 matchingCount = CryptoUtils._getMatchingIds(_packPVPData(), uint64(PVP_INTERVAL), _computeCycleSkip(), uint64(RATING_EXPAND_INTERVAL));
return matchingCount == 0;
}
/*
* @title startPVP enqueues specified warrior to PVP
*
* @dev When the owner enqueues his warrior for PvP, the warrior enters the waiting room.
* Once every 15 minutes, we check the warriors in the room and select pairs.
* For those warriors to whom we found couples, fighting is conducted and the results
* are recorded in the profile of the warrior.
*/
function addPVPContender(address _owner, uint256 _packedWarrior) external payable whenNotPaused {
// Caller must be pvpListener contract
require(msg.sender == address(pvpListener));
require(_owner != address(0));
//contender can be added only while PVP is scheduled in future
//or no matching warrior pairs found
require(nextPVPBatleBlock > block.number || _noMatchingPairs());
// Check that the warrior exists.
require(_packedWarrior != 0);
//owner must withdraw all loot before contending pvp
require(ownerToBooty[_owner] == 0);
//check that there is enough room for new participants
require(pvpQueueSize < pvpQueue.length);
// Checks for payment.
uint256 fee = _getPVPFeeByLevel(CryptoUtils._unpackLevelValue(_packedWarrior));
require(msg.value >= fee);
//
// All checks passed, put the warrior to the queue!
_triggerNewPVPContender(_owner, _packedWarrior, fee);
}
function _packPVPData() internal view returns(uint256[] memory matchingIds) {
uint256 length = pvpQueueSize;
matchingIds = new uint256[](length);
for(uint256 i = 0; i < length; i++) {
matchingIds[i] = pvpQueue[i];
}
return matchingIds;
}
function _computeTotalBooty(uint256[] memory _packedWarriors, uint256 matchingCount) internal view returns(uint256) {
//compute session booty
uint256 sessionLoot = 0;
for(uint256 i = 0; i < matchingCount; i++) {
sessionLoot += _getPVPFeeByLevel(CryptoUtils._unpackLevelValue(_packedWarriors[i]));
}
return sessionLoot;
}
function _grandPVPRewards(uint256[] memory _packedWarriors, uint256 matchingCount)
internal returns(uint256)
{
uint256 booty = 0;
uint256 packedWarrior;
uint256 failedBooty = 0;
uint256 sessionBooty = _computeTotalBooty(_packedWarriors, matchingCount);
uint256 incentiveCut = _computeIncentiveCut(sessionBooty, pvpMaxIncentiveCut);
uint256 contendersCut = _getPVPContendersCut(incentiveCut);
for(uint256 id = 0; id < matchingCount; id++) {
//give reward to warriors that fought hard
//winner, even ids are winners!
packedWarrior = _packedWarriors[id];
//
//give winner deserved booty 80% from both bets
//must be computed before level reward!
booty = _getPVPFeeByLevel(CryptoUtils._unpackLevelValue(packedWarrior)) +
_getPVPFeeByLevel(CryptoUtils._unpackLevelValue(_packedWarriors[id + 1]));
//
//send reward to warrior owner
failedBooty += sendBooty(warriorToOwner[CryptoUtils._unpackIdValue(packedWarrior)], _computePVPReward(booty, contendersCut));
//loser, they are odd...
//skip them, as they deserve none!
id ++;
}
failedBooty += sendBooty(pvpListener.getBeneficiary(), _computePVPBeneficiaryFee(sessionBooty));
if (failedBooty > 0) {
totalBooty += failedBooty;
}
//if tournament admission start time not passed
//add tournament cut to current tournament bank,
//otherwise to next tournament bank
if (getTournamentAdmissionBlock() > block.number) {
currentTournamentBank += _computeTournamentCut(sessionBooty);
} else {
nextTournamentBank += _computeTournamentCut(sessionBooty);
}
//compute incentive reward
return _computeIncentiveReward(sessionBooty, incentiveCut);
}
function _increaseCycleAndTrimQueue(uint256[] memory matchingIds, uint256 matchingCount) internal {
uint32 length = uint32(matchingIds.length - matchingCount);
uint256 packedWarrior;
uint256 skipCycles = _computeCycleSkip();
for(uint256 i = 0; i < length; i++) {
packedWarrior = matchingIds[matchingCount + i];
//increase warrior iteration cycle
pvpQueue[i] = CryptoUtils._changeCycleValue(packedWarrior, CryptoUtils._unpackCycleValue(packedWarrior) + skipCycles);
}
//trim queue
pvpQueueSize = length;
}
function _computeCycleSkip() internal view returns(uint256) {
uint256 number = block.number;
return nextPVPBatleBlock > number ? 0 : (number - nextPVPBatleBlock) * secondsPerBlock / PVP_INTERVAL + 1;
}
function _getWarriorOwners(uint256[] memory pvpData) internal view returns (address[] memory owners){
uint256 length = pvpData.length;
owners = new address[](length);
for(uint256 i = 0; i < length; i ++) {
owners[i] = warriorToOwner[CryptoUtils._unpackIdValue(pvpData[i])];
}
}
// @dev Internal utility function to initiate pvp battle, assumes that all battle
/// requirements have been checked.
function _triggerPVPFinish(uint256[] memory pvpData, uint256 matchingCount) internal returns(uint256){
//
//compute battle results
CryptoUtils._getPVPBattleResults(pvpData, matchingCount, nextPVPBatleBlock);
//
//mark not fought warriors and trim queue
_increaseCycleAndTrimQueue(pvpData, matchingCount);
//
//schedule next battle time
nextPVPBatleBlock = (PVP_INTERVAL / secondsPerBlock) + block.number;
//
//schedule tournament
//if contendersCount is 0 and tournament not scheduled, schedule tournament
//NB MUST be before _grandPVPRewards()
_scheduleTournament();
// compute and grand rewards to warriors,
// put tournament cut to bank, not susceptible to reentry attack because of require(nextPVPBatleBlock <= block.number);
// and require(number of pairs > 1);
uint256 incentiveReward = _grandPVPRewards(pvpData, matchingCount);
//
//notify pvp listener contract
pvpListener.pvpFinished(pvpData, matchingCount);
//
//fire event
PVPFinished(pvpData, _getWarriorOwners(pvpData), matchingCount);
PVPScheduled(nextPVPBatleBlock);
return incentiveReward;
}
/**
* @dev finishPVP this method finds matches of warrior pairs
* in waiting room and computes result of their fights.
*
* The winner gets +1 level, the loser gets +0.5 level
* The winning player gets +130 rating
* The losing player gets -30 or 70 rating (if warrior levelUps after battle) .
* can be called once in 15min.
* NB If the warrior is not picked up in an hour, then we expand the range
* of selection by 25 rating each hour.
*/
function finishPVP() public whenNotPaused {
// battle interval is over
require(nextPVPBatleBlock <= block.number);
//
//match warriors
uint256[] memory pvpData = _packPVPData();
//match ids and sort them according to matching
uint256 matchingCount = CryptoUtils._getMatchingIds(pvpData, uint64(PVP_INTERVAL), _computeCycleSkip(), uint64(RATING_EXPAND_INTERVAL));
// we have at least 1 matching battle pair
require(matchingCount > 1);
// When the all checks done, calculate actual battle result
uint256 incentiveReward = _triggerPVPFinish(pvpData, matchingCount);
//give reward for incentive
safeSend(msg.sender, incentiveReward);
}
// @dev Removes specified warrior from PVP queue
// sets warrior free (IDLE) and returns pvp entrance fee to owner
// @notice This is a state-modifying function that can
// be called while the contract is paused.
// @param _warriorId - ID of warrior in PVP queue
function removePVPContender(uint32 _warriorId) external{
uint256 queueSize = pvpQueueSize;
require(queueSize > 0);
// Caller must be owner of the specified warrior
require(warriorToOwner[_warriorId] == msg.sender);
//warrior must be in pvp queue
int256 warriorIndex = indexOf(_warriorId);
require(warriorIndex >= 0);
//grab warrior data
uint256 warriorData = pvpQueue[uint32(warriorIndex)];
//warrior cycle must be >= 4 (> than 1 hour)
require((CryptoUtils._unpackCycleValue(warriorData) + _computeCycleSkip()) >= 4);
//remove from queue
if (uint256(warriorIndex) < queueSize - 1) {
pvpQueue[uint32(warriorIndex)] = pvpQueue[pvpQueueSize - 1];
}
pvpQueueSize --;
//notify battle listener
pvpListener.pvpContenderRemoved(_warriorId);
//return pvp bet
msg.sender.transfer(_getPVPFeeByLevel(CryptoUtils._unpackLevelValue(warriorData)));
//Emit event
PVPContenderRemoved(_warriorId, msg.sender);
}
function getPVPCycles(uint32[] warriorIds) external view returns(uint32[]){
uint256 length = warriorIds.length;
uint32[] memory cycles = new uint32[](length);
int256 index;
uint256 skipCycles = _computeCycleSkip();
for(uint256 i = 0; i < length; i ++) {
index = indexOf(warriorIds[i]);
cycles[i] = index >= 0 ? uint32(CryptoUtils._unpackCycleValue(pvpQueue[uint32(index)]) + skipCycles) : 0;
}
return cycles;
}
// @dev Remove all PVP contenders from PVP queue
// and return all bets to warrior owners.
// NB: this is emergency method, used only in f%#^@up situation
function removeAllPVPContenders() external onlyOwner whenPaused {
//remove all pvp contenders
uint256 length = pvpQueueSize;
uint256 warriorData;
uint256 warriorId;
uint256 failedBooty;
address owner;
pvpQueueSize = 0;
for(uint256 i = 0; i < length; i++) {
//grab warrior data
warriorData = pvpQueue[i];
warriorId = CryptoUtils._unpackIdValue(warriorData);
//notify battle listener
pvpListener.pvpContenderRemoved(uint32(warriorId));
owner = warriorToOwner[warriorId];
//return pvp bet
failedBooty += sendBooty(owner, _getPVPFeeByLevel(CryptoUtils._unpackLevelValue(warriorData)));
}
totalBooty += failedBooty;
}
}
contract Tournament is PVP {
uint256 internal constant GROUP_SIZE = 5;
uint256 internal constant DATA_SIZE = 2;
uint256 internal constant THRESHOLD = 300;
/** list of warrior IDs that will participate in next tournament.
* Fixed size arry, to evade constant remove and push operations,
* this approach reduces transaction costs involving array modification. */
uint256[160] public tournamentQueue;
/**The cost of participation in the tournament is 1% of its current prize fund,
* money is added to the prize fund. measured in basis points (1/100 of a percent).
* Values 0-10,000 map to 0%-100% */
uint256 internal tournamentEntranceFeeCut = 100;
// Values 0-10,000 map to 0%-100% => 20%
uint256 public tournamentOwnersCut;
uint256 public tournamentIncentiveCut;
/** @dev TournamentNewContender event. Emitted every time a warrior enters tournament
* @param owner Warrior owner
* @param warriorIds 5 Warrior IDs that entered tournament, packed into one uint256
* see CryptoUtils._packWarriorIds
*/
event TournamentNewContender(address owner, uint256 warriorIds, uint256 entranceFee);
/** @dev TournamentFinished event. Emitted every time a tournament is finished
* @param owners array of warrior group owners packed to uint256
* @param results number of wins for each group
* @param tournamentBank current tournament bank
* see CryptoUtils._packWarriorIds
*/
event TournamentFinished(uint256[] owners, uint32[] results, uint256 tournamentBank);
function Tournament(uint256 _pvpCut, uint256 _tournamentBankCut,
uint256 _pvpMaxIncentiveCut, uint256 _tournamentOwnersCut, uint256 _tournamentIncentiveCut) public
PVP(_pvpCut, _tournamentBankCut, _pvpMaxIncentiveCut)
{
require((_tournamentOwnersCut + _tournamentIncentiveCut) <= 10000);
tournamentOwnersCut = _tournamentOwnersCut;
tournamentIncentiveCut = _tournamentIncentiveCut;
}
// @dev Computes incentive reward for launching tournament finishTournament()
// @param _tournamentBank
function _computeTournamentIncentiveReward(uint256 _currentBank, uint256 _incentiveCut) internal pure returns (uint256){
// NOTE: We don't use SafeMath (or similar) in this function because _currentBank max is equal ~ 20000000 finney,
// and (tournamentOwnersCut + tournamentIncentiveCut) <= 10000 (see the require()
// statement in the Tournament constructor). The result of this
// function is always guaranteed to be <= _currentBank.
return _currentBank * _incentiveCut / 10000;
}
function _computeTournamentContenderCut(uint256 _incentiveCut) internal view returns (uint256) {
// NOTE: (tournamentOwnersCut + tournamentIncentiveCut) <= 10000 (see the require()
// statement in the Tournament constructor). The result of this
// function is always guaranteed to be <= _reward.
return 10000 - tournamentOwnersCut - _incentiveCut;
}
function _computeTournamentBeneficiaryFee(uint256 _currentBank) internal view returns (uint256){
// NOTE: We don't use SafeMath (or similar) in this function because _currentBank max is equal ~ 20000000 finney,
// and (tournamentOwnersCut + tournamentIncentiveCut) <= 10000 (see the require()
// statement in the Tournament constructor). The result of this
// function is always guaranteed to be <= _currentBank.
return _currentBank * tournamentOwnersCut / 10000;
}
// @dev set tournament entrance fee cut, can be set only if
// tournament queue is empty
// @param _cut range from 0 - 10000, mapped to 0-100%
function setTournamentEntranceFeeCut(uint256 _cut) external onlyOwner {
//cut must be less or equal 100&
require(_cut <= 10000);
//tournament queue must be empty
require(tournamentQueueSize == 0);
//checks passed, set cut
tournamentEntranceFeeCut = _cut;
}
function getTournamentEntranceFee() external view returns(uint256) {
return currentTournamentBank * tournamentEntranceFeeCut / 10000;
}
//@dev returns tournament entrance fee - 3% threshold
function getTournamentThresholdFee() public view returns(uint256) {
return currentTournamentBank * tournamentEntranceFeeCut * (10000 - THRESHOLD) / 10000 / 10000;
}
//@dev returns max allowed tournament contenders, public because of internal use
function maxTournamentContenders() public view returns(uint256){
return tournamentQueue.length / DATA_SIZE;
}
function canFinishTournament() external view returns(bool) {
return tournamentEndBlock <= block.number && tournamentQueueSize > 0;
}
// @dev Internal utility function to sigin up to tournament,
// assumes that all battle requirements have been checked.
function _triggerNewTournamentContender(address _owner, uint256[] memory _tournamentData, uint256 _fee) internal {
//pack warrior ids into uint256
currentTournamentBank += _fee;
uint256 packedWarriorIds = CryptoUtils._packWarriorIds(_tournamentData);
//make composite warrior out of 5 warriors
uint256 combinedWarrior = CryptoUtils._combineWarriors(_tournamentData);
//add to queue
//icrement tournament queue
uint256 size = tournamentQueueSize++ * DATA_SIZE;
//record tournament data
tournamentQueue[size++] = packedWarriorIds;
tournamentQueue[size++] = combinedWarrior;
warriorToOwner[CryptoUtils._unpackWarriorId(packedWarriorIds, 0)] = _owner;
//
//Emit event
TournamentNewContender(_owner, packedWarriorIds, _fee);
}
function addTournamentContender(address _owner, uint256[] _tournamentData) external payable whenNotPaused{
// Caller must be pvpListener contract
require(msg.sender == address(pvpListener));
require(_owner != address(0));
//
//check current tournament bank > 0
require(pvpBattleFee == 0 || currentTournamentBank > 0);
//
//check that there is enough funds to pay entrance fee
uint256 fee = getTournamentThresholdFee();
require(msg.value >= fee);
//owner must withdraw all booty before contending pvp
require(ownerToBooty[_owner] == 0);
//
//check that warriors group is exactly of allowed size
require(_tournamentData.length == GROUP_SIZE);
//
//check that there is enough room for new participants
require(tournamentQueueSize < maxTournamentContenders());
//
//check that admission started
require(block.number >= getTournamentAdmissionBlock());
//check that admission not ended
require(block.number <= tournamentEndBlock);
//all checks passed, trigger sign up
_triggerNewTournamentContender(_owner, _tournamentData, fee);
}
//@dev collect all combined warriors data
function getCombinedWarriors() internal view returns(uint256[] memory warriorsData) {
uint256 length = tournamentQueueSize;
warriorsData = new uint256[](length);
for(uint256 i = 0; i < length; i ++) {
// Grab the combined warrior data in storage.
warriorsData[i] = tournamentQueue[i * DATA_SIZE + 1];
}
return warriorsData;
}
function getTournamentState() external view returns
(uint256 contendersCount, uint256 bank, uint256 admissionStartBlock, uint256 endBlock, uint256 incentiveReward)
{
contendersCount = tournamentQueueSize;
bank = currentTournamentBank;
admissionStartBlock = getTournamentAdmissionBlock();
endBlock = tournamentEndBlock;
incentiveReward = _computeTournamentIncentiveReward(bank, _computeIncentiveCut(bank, tournamentIncentiveCut));
}
function _repackToCombinedIds(uint256[] memory _warriorsData) internal view {
uint256 length = _warriorsData.length;
for(uint256 i = 0; i < length; i ++) {
_warriorsData[i] = tournamentQueue[i * DATA_SIZE];
}
}
// @dev Computes warrior pvp reward
// @param _totalBet - total bet from both competitors.
function _computeTournamentBooty(uint256 _currentBank, uint256 _contenderResult, uint256 _totalBattles) internal pure returns (uint256){
// NOTE: We don't use SafeMath (or similar) in this function because _currentBank max is equal ~ 20000000 finney,
// _totalBattles is guaranteed to be > 0 and <= 400, and (tournamentOwnersCut + tournamentIncentiveCut) <= 10000 (see the require()
// statement in the Tournament constructor). The result of this
// function is always guaranteed to be <= _reward.
// return _currentBank * (10000 - tournamentOwnersCut - _incentiveCut) * _result / 10000 / _totalBattles;
return _currentBank * _contenderResult / _totalBattles;
}
function _grandTournamentBooty(uint256 _warriorIds, uint256 _currentBank, uint256 _contenderResult, uint256 _totalBattles)
internal returns (uint256)
{
uint256 warriorId = CryptoUtils._unpackWarriorId(_warriorIds, 0);
address owner = warriorToOwner[warriorId];
uint256 booty = _computeTournamentBooty(_currentBank, _contenderResult, _totalBattles);
return sendBooty(owner, booty);
}
function _grandTournamentRewards(uint256 _currentBank, uint256[] memory _warriorsData, uint32[] memory _results) internal returns (uint256){
uint256 length = _warriorsData.length;
uint256 totalBattles = CryptoUtils._getTournamentBattles(length) * 10000;//*10000 required for booty computation
uint256 incentiveCut = _computeIncentiveCut(_currentBank, tournamentIncentiveCut);
uint256 contenderCut = _computeTournamentContenderCut(incentiveCut);
uint256 failedBooty = 0;
for(uint256 i = 0; i < length; i ++) {
//grand rewards
failedBooty += _grandTournamentBooty(_warriorsData[i], _currentBank, _results[i] * contenderCut, totalBattles);
}
//send beneficiary fee
failedBooty += sendBooty(pvpListener.getBeneficiary(), _computeTournamentBeneficiaryFee(_currentBank));
if (failedBooty > 0) {
totalBooty += failedBooty;
}
return _computeTournamentIncentiveReward(_currentBank, incentiveCut);
}
function _repackToWarriorOwners(uint256[] memory warriorsData) internal view {
uint256 length = warriorsData.length;
for (uint256 i = 0; i < length; i ++) {
warriorsData[i] = uint256(warriorToOwner[CryptoUtils._unpackWarriorId(warriorsData[i], 0)]);
}
}
function _triggerFinishTournament() internal returns(uint256){
//hold 10 random battles for each composite warrior
uint256[] memory warriorsData = getCombinedWarriors();
uint32[] memory results = CryptoUtils.getTournamentBattleResults(warriorsData, tournamentEndBlock - 1);
//repack combined warriors id
_repackToCombinedIds(warriorsData);
//notify pvp listener
pvpListener.tournamentFinished(warriorsData);
//reschedule
//clear tournament
tournamentQueueSize = 0;
//schedule new tournament
_scheduleTournament();
uint256 currentBank = currentTournamentBank;
currentTournamentBank = 0;//nullify before sending to users
//grand rewards, not susceptible to reentry attack
//because of require(tournamentEndBlock <= block.number)
//and require(tournamentQueueSize > 0) and currentTournamentBank == 0
uint256 incentiveReward = _grandTournamentRewards(currentBank, warriorsData, results);
currentTournamentBank = nextTournamentBank;
nextTournamentBank = 0;
_repackToWarriorOwners(warriorsData);
//emit event
TournamentFinished(warriorsData, results, currentBank);
return incentiveReward;
}
function finishTournament() external whenNotPaused {
//make all the checks
// tournament is ready to be executed
require(tournamentEndBlock <= block.number);
// we have participants
require(tournamentQueueSize > 0);
uint256 incentiveReward = _triggerFinishTournament();
//give reward for incentive
safeSend(msg.sender, incentiveReward);
}
// @dev Remove all PVP contenders from PVP queue
// and return all entrance fees to warrior owners.
// NB: this is emergency method, used only in f%#^@up situation
function removeAllTournamentContenders() external onlyOwner whenPaused {
//remove all pvp contenders
uint256 length = tournamentQueueSize;
uint256 warriorId;
uint256 failedBooty;
uint256 i;
uint256 fee;
uint256 bank = currentTournamentBank;
uint256[] memory warriorsData = new uint256[](length);
//get tournament warriors
for(i = 0; i < length; i ++) {
warriorsData[i] = tournamentQueue[i * DATA_SIZE];
}
//notify pvp listener
pvpListener.tournamentFinished(warriorsData);
//return entrance fee to warrior owners
currentTournamentBank = 0;
tournamentQueueSize = 0;
for(i = length - 1; i >= 0; i --) {
//return entrance fee
warriorId = CryptoUtils._unpackWarriorId(warriorsData[i], 0);
//compute contender entrance fee
fee = bank - (bank * 10000 / (tournamentEntranceFeeCut * (10000 - THRESHOLD) / 10000 + 10000));
//return entrance fee to owner
failedBooty += sendBooty(warriorToOwner[warriorId], fee);
//subtract fee from bank, for next use
bank -= fee;
}
currentTournamentBank = bank;
totalBooty += failedBooty;
}
}
contract BattleProvider is Tournament {
function BattleProvider(address _pvpListener, uint256 _pvpCut, uint256 _tournamentCut, uint256 _incentiveCut,
uint256 _tournamentOwnersCut, uint256 _tournamentIncentiveCut) public
Tournament(_pvpCut, _tournamentCut, _incentiveCut, _tournamentOwnersCut, _tournamentIncentiveCut)
{
PVPListenerInterface candidateContract = PVPListenerInterface(_pvpListener);
// NOTE: verify that a contract is what we expect - https://github.com/Lunyr/crowdsale-contracts/blob/cfadd15986c30521d8ba7d5b6f57b4fefcc7ac38/contracts/LunyrToken.sol#L117
require(candidateContract.isPVPListener());
// Set the new contract address
pvpListener = candidateContract;
paused = true;
// the creator of the contract is the initial owner
owner = msg.sender;
}
// @dev Sanity check that allows us to ensure that we are pointing to the
// right BattleProvider in our setBattleProviderAddress() call.
function isPVPProvider() external pure returns (bool) {
return true;
}
/// @dev Override unpause so it requires all external contract addresses
/// to be set before contract can be unpaused.
/// @notice This is public rather than external so we can call super.unpause
/// without using an expensive CALL.
function unpause() public onlyOwner whenPaused {
require(address(pvpListener) != address(0));
// Actually unpause the contract.
super.unpause();
}
function setSecondsPerBlock(uint256 secs) external onlyOwner {
secondsPerBlock = secs;
}
}
library CryptoUtils {
/* CLASSES */
uint256 internal constant WARRIOR = 0;
uint256 internal constant ARCHER = 1;
uint256 internal constant MAGE = 2;
/* RARITIES */
uint256 internal constant COMMON = 1;
uint256 internal constant UNCOMMON = 2;
uint256 internal constant RARE = 3;
uint256 internal constant MYTHIC = 4;
uint256 internal constant LEGENDARY = 5;
uint256 internal constant UNIQUE = 6;
/* LIMITS */
uint256 internal constant CLASS_MECHANICS_MAX = 3;
uint256 internal constant RARITY_MAX = 6;
/*@dev range used for rarity chance computation */
uint256 internal constant RARITY_CHANCE_RANGE = 10000000;
uint256 internal constant POINTS_TO_LEVEL = 10;
/* ATTRIBUTE MASKS */
/*@dev range 0-9999 */
uint256 internal constant UNIQUE_MASK_0 = 1;
/*@dev range 0-9 */
uint256 internal constant RARITY_MASK_1 = UNIQUE_MASK_0 * 10000;
/*@dev range 0-999 */
uint256 internal constant CLASS_VIEW_MASK_2 = RARITY_MASK_1 * 10;
/*@dev range 0-999 */
uint256 internal constant BODY_COLOR_MASK_3 = CLASS_VIEW_MASK_2 * 1000;
/*@dev range 0-999 */
uint256 internal constant EYES_MASK_4 = BODY_COLOR_MASK_3 * 1000;
/*@dev range 0-999 */
uint256 internal constant MOUTH_MASK_5 = EYES_MASK_4 * 1000;
/*@dev range 0-999 */
uint256 internal constant HEIR_MASK_6 = MOUTH_MASK_5 * 1000;
/*@dev range 0-999 */
uint256 internal constant HEIR_COLOR_MASK_7 = HEIR_MASK_6 * 1000;
/*@dev range 0-999 */
uint256 internal constant ARMOR_MASK_8 = HEIR_COLOR_MASK_7 * 1000;
/*@dev range 0-999 */
uint256 internal constant WEAPON_MASK_9 = ARMOR_MASK_8 * 1000;
/*@dev range 0-999 */
uint256 internal constant HAT_MASK_10 = WEAPON_MASK_9 * 1000;
/*@dev range 0-99 */
uint256 internal constant RUNES_MASK_11 = HAT_MASK_10 * 1000;
/*@dev range 0-99 */
uint256 internal constant WINGS_MASK_12 = RUNES_MASK_11 * 100;
/*@dev range 0-99 */
uint256 internal constant PET_MASK_13 = WINGS_MASK_12 * 100;
/*@dev range 0-99 */
uint256 internal constant BORDER_MASK_14 = PET_MASK_13 * 100;
/*@dev range 0-99 */
uint256 internal constant BACKGROUND_MASK_15 = BORDER_MASK_14 * 100;
/*@dev range 0-99 */
uint256 internal constant INTELLIGENCE_MASK_16 = BACKGROUND_MASK_15 * 100;
/*@dev range 0-99 */
uint256 internal constant AGILITY_MASK_17 = INTELLIGENCE_MASK_16 * 100;
/*@dev range 0-99 */
uint256 internal constant STRENGTH_MASK_18 = AGILITY_MASK_17 * 100;
/*@dev range 0-9 */
uint256 internal constant CLASS_MECH_MASK_19 = STRENGTH_MASK_18 * 100;
/*@dev range 0-999 */
uint256 internal constant RARITY_BONUS_MASK_20 = CLASS_MECH_MASK_19 * 10;
/*@dev range 0-9 */
uint256 internal constant SPECIALITY_MASK_21 = RARITY_BONUS_MASK_20 * 1000;
/*@dev range 0-99 */
uint256 internal constant DAMAGE_MASK_22 = SPECIALITY_MASK_21 * 10;
/*@dev range 0-99 */
uint256 internal constant AURA_MASK_23 = DAMAGE_MASK_22 * 100;
/*@dev 20 decimals left */
uint256 internal constant BASE_MASK_24 = AURA_MASK_23 * 100;
/* SPECIAL PERKS */
uint256 internal constant MINER_PERK = 1;
/* PARAM INDEXES */
uint256 internal constant BODY_COLOR_MAX_INDEX_0 = 0;
uint256 internal constant EYES_MAX_INDEX_1 = 1;
uint256 internal constant MOUTH_MAX_2 = 2;
uint256 internal constant HAIR_MAX_3 = 3;
uint256 internal constant HEIR_COLOR_MAX_4 = 4;
uint256 internal constant ARMOR_MAX_5 = 5;
uint256 internal constant WEAPON_MAX_6 = 6;
uint256 internal constant HAT_MAX_7 = 7;
uint256 internal constant RUNES_MAX_8 = 8;
uint256 internal constant WINGS_MAX_9 = 9;
uint256 internal constant PET_MAX_10 = 10;
uint256 internal constant BORDER_MAX_11 = 11;
uint256 internal constant BACKGROUND_MAX_12 = 12;
uint256 internal constant UNIQUE_INDEX_13 = 13;
uint256 internal constant LEGENDARY_INDEX_14 = 14;
uint256 internal constant MYTHIC_INDEX_15 = 15;
uint256 internal constant RARE_INDEX_16 = 16;
uint256 internal constant UNCOMMON_INDEX_17 = 17;
uint256 internal constant UNIQUE_TOTAL_INDEX_18 = 18;
/* PACK PVP DATA LOGIC */
//pvp data
uint256 internal constant CLASS_PACK_0 = 1;
uint256 internal constant RARITY_BONUS_PACK_1 = CLASS_PACK_0 * 10;
uint256 internal constant RARITY_PACK_2 = RARITY_BONUS_PACK_1 * 1000;
uint256 internal constant EXPERIENCE_PACK_3 = RARITY_PACK_2 * 10;
uint256 internal constant INTELLIGENCE_PACK_4 = EXPERIENCE_PACK_3 * 1000;
uint256 internal constant AGILITY_PACK_5 = INTELLIGENCE_PACK_4 * 100;
uint256 internal constant STRENGTH_PACK_6 = AGILITY_PACK_5 * 100;
uint256 internal constant BASE_DAMAGE_PACK_7 = STRENGTH_PACK_6 * 100;
uint256 internal constant PET_PACK_8 = BASE_DAMAGE_PACK_7 * 100;
uint256 internal constant AURA_PACK_9 = PET_PACK_8 * 100;
uint256 internal constant WARRIOR_ID_PACK_10 = AURA_PACK_9 * 100;
uint256 internal constant PVP_CYCLE_PACK_11 = WARRIOR_ID_PACK_10 * 10**10;
uint256 internal constant RATING_PACK_12 = PVP_CYCLE_PACK_11 * 10**10;
uint256 internal constant PVP_BASE_PACK_13 = RATING_PACK_12 * 10**10;//NB rating must be at the END!
//tournament data
uint256 internal constant HP_PACK_0 = 1;
uint256 internal constant DAMAGE_PACK_1 = HP_PACK_0 * 10**12;
uint256 internal constant ARMOR_PACK_2 = DAMAGE_PACK_1 * 10**12;
uint256 internal constant DODGE_PACK_3 = ARMOR_PACK_2 * 10**12;
uint256 internal constant PENETRATION_PACK_4 = DODGE_PACK_3 * 10**12;
uint256 internal constant COMBINE_BASE_PACK_5 = PENETRATION_PACK_4 * 10**12;
/* MISC CONSTANTS */
uint256 internal constant MAX_ID_SIZE = 10000000000;
int256 internal constant PRECISION = 1000000;
uint256 internal constant BATTLES_PER_CONTENDER = 10;//10x100
uint256 internal constant BATTLES_PER_CONTENDER_SUM = BATTLES_PER_CONTENDER * 100;//10x100
uint256 internal constant LEVEL_BONUSES = 98898174676155504541373431282523211917151413121110;
//ucommon bonuses
uint256 internal constant BONUS_NONE = 0;
uint256 internal constant BONUS_HP = 1;
uint256 internal constant BONUS_ARMOR = 2;
uint256 internal constant BONUS_CRIT_CHANCE = 3;
uint256 internal constant BONUS_CRIT_MULT = 4;
uint256 internal constant BONUS_PENETRATION = 5;
//rare bonuses
uint256 internal constant BONUS_STR = 6;
uint256 internal constant BONUS_AGI = 7;
uint256 internal constant BONUS_INT = 8;
uint256 internal constant BONUS_DAMAGE = 9;
//bonus value database,
uint256 internal constant BONUS_DATA = 16060606140107152000;
//pets database
uint256 internal constant PETS_DATA = 287164235573728325842459981692000;
uint256 internal constant PET_AURA = 2;
uint256 internal constant PET_PARAM_1 = 1;
uint256 internal constant PET_PARAM_2 = 0;
/* GETTERS */
function getUniqueValue(uint256 identity) internal pure returns(uint256){
return identity % RARITY_MASK_1;
}
function getRarityValue(uint256 identity) internal pure returns(uint256){
return (identity % CLASS_VIEW_MASK_2) / RARITY_MASK_1;
}
function getClassViewValue(uint256 identity) internal pure returns(uint256){
return (identity % BODY_COLOR_MASK_3) / CLASS_VIEW_MASK_2;
}
function getBodyColorValue(uint256 identity) internal pure returns(uint256){
return (identity % EYES_MASK_4) / BODY_COLOR_MASK_3;
}
function getEyesValue(uint256 identity) internal pure returns(uint256){
return (identity % MOUTH_MASK_5) / EYES_MASK_4;
}
function getMouthValue(uint256 identity) internal pure returns(uint256){
return (identity % HEIR_MASK_6) / MOUTH_MASK_5;
}
function getHairValue(uint256 identity) internal pure returns(uint256){
return (identity % HEIR_COLOR_MASK_7) / HEIR_MASK_6;
}
function getHairColorValue(uint256 identity) internal pure returns(uint256){
return (identity % ARMOR_MASK_8) / HEIR_COLOR_MASK_7;
}
function getArmorValue(uint256 identity) internal pure returns(uint256){
return (identity % WEAPON_MASK_9) / ARMOR_MASK_8;
}
function getWeaponValue(uint256 identity) internal pure returns(uint256){
return (identity % HAT_MASK_10) / WEAPON_MASK_9;
}
function getHatValue(uint256 identity) internal pure returns(uint256){
return (identity % RUNES_MASK_11) / HAT_MASK_10;
}
function getRunesValue(uint256 identity) internal pure returns(uint256){
return (identity % WINGS_MASK_12) / RUNES_MASK_11;
}
function getWingsValue(uint256 identity) internal pure returns(uint256){
return (identity % PET_MASK_13) / WINGS_MASK_12;
}
function getPetValue(uint256 identity) internal pure returns(uint256){
return (identity % BORDER_MASK_14) / PET_MASK_13;
}
function getBorderValue(uint256 identity) internal pure returns(uint256){
return (identity % BACKGROUND_MASK_15) / BORDER_MASK_14;
}
function getBackgroundValue(uint256 identity) internal pure returns(uint256){
return (identity % INTELLIGENCE_MASK_16) / BACKGROUND_MASK_15;
}
function getIntelligenceValue(uint256 identity) internal pure returns(uint256){
return (identity % AGILITY_MASK_17) / INTELLIGENCE_MASK_16;
}
function getAgilityValue(uint256 identity) internal pure returns(uint256){
return ((identity % STRENGTH_MASK_18) / AGILITY_MASK_17);
}
function getStrengthValue(uint256 identity) internal pure returns(uint256){
return ((identity % CLASS_MECH_MASK_19) / STRENGTH_MASK_18);
}
function getClassMechValue(uint256 identity) internal pure returns(uint256){
return (identity % RARITY_BONUS_MASK_20) / CLASS_MECH_MASK_19;
}
function getRarityBonusValue(uint256 identity) internal pure returns(uint256){
return (identity % SPECIALITY_MASK_21) / RARITY_BONUS_MASK_20;
}
function getSpecialityValue(uint256 identity) internal pure returns(uint256){
return (identity % DAMAGE_MASK_22) / SPECIALITY_MASK_21;
}
function getDamageValue(uint256 identity) internal pure returns(uint256){
return (identity % AURA_MASK_23) / DAMAGE_MASK_22;
}
function getAuraValue(uint256 identity) internal pure returns(uint256){
return ((identity % BASE_MASK_24) / AURA_MASK_23);
}
/* SETTERS */
function _setUniqueValue0(uint256 value) internal pure returns(uint256){
require(value < RARITY_MASK_1);
return value * UNIQUE_MASK_0;
}
function _setRarityValue1(uint256 value) internal pure returns(uint256){
require(value < (CLASS_VIEW_MASK_2 / RARITY_MASK_1));
return value * RARITY_MASK_1;
}
function _setClassViewValue2(uint256 value) internal pure returns(uint256){
require(value < (BODY_COLOR_MASK_3 / CLASS_VIEW_MASK_2));
return value * CLASS_VIEW_MASK_2;
}
function _setBodyColorValue3(uint256 value) internal pure returns(uint256){
require(value < (EYES_MASK_4 / BODY_COLOR_MASK_3));
return value * BODY_COLOR_MASK_3;
}
function _setEyesValue4(uint256 value) internal pure returns(uint256){
require(value < (MOUTH_MASK_5 / EYES_MASK_4));
return value * EYES_MASK_4;
}
function _setMouthValue5(uint256 value) internal pure returns(uint256){
require(value < (HEIR_MASK_6 / MOUTH_MASK_5));
return value * MOUTH_MASK_5;
}
function _setHairValue6(uint256 value) internal pure returns(uint256){
require(value < (HEIR_COLOR_MASK_7 / HEIR_MASK_6));
return value * HEIR_MASK_6;
}
function _setHairColorValue7(uint256 value) internal pure returns(uint256){
require(value < (ARMOR_MASK_8 / HEIR_COLOR_MASK_7));
return value * HEIR_COLOR_MASK_7;
}
function _setArmorValue8(uint256 value) internal pure returns(uint256){
require(value < (WEAPON_MASK_9 / ARMOR_MASK_8));
return value * ARMOR_MASK_8;
}
function _setWeaponValue9(uint256 value) internal pure returns(uint256){
require(value < (HAT_MASK_10 / WEAPON_MASK_9));
return value * WEAPON_MASK_9;
}
function _setHatValue10(uint256 value) internal pure returns(uint256){
require(value < (RUNES_MASK_11 / HAT_MASK_10));
return value * HAT_MASK_10;
}
function _setRunesValue11(uint256 value) internal pure returns(uint256){
require(value < (WINGS_MASK_12 / RUNES_MASK_11));
return value * RUNES_MASK_11;
}
function _setWingsValue12(uint256 value) internal pure returns(uint256){
require(value < (PET_MASK_13 / WINGS_MASK_12));
return value * WINGS_MASK_12;
}
function _setPetValue13(uint256 value) internal pure returns(uint256){
require(value < (BORDER_MASK_14 / PET_MASK_13));
return value * PET_MASK_13;
}
function _setBorderValue14(uint256 value) internal pure returns(uint256){
require(value < (BACKGROUND_MASK_15 / BORDER_MASK_14));
return value * BORDER_MASK_14;
}
function _setBackgroundValue15(uint256 value) internal pure returns(uint256){
require(value < (INTELLIGENCE_MASK_16 / BACKGROUND_MASK_15));
return value * BACKGROUND_MASK_15;
}
function _setIntelligenceValue16(uint256 value) internal pure returns(uint256){
require(value < (AGILITY_MASK_17 / INTELLIGENCE_MASK_16));
return value * INTELLIGENCE_MASK_16;
}
function _setAgilityValue17(uint256 value) internal pure returns(uint256){
require(value < (STRENGTH_MASK_18 / AGILITY_MASK_17));
return value * AGILITY_MASK_17;
}
function _setStrengthValue18(uint256 value) internal pure returns(uint256){
require(value < (CLASS_MECH_MASK_19 / STRENGTH_MASK_18));
return value * STRENGTH_MASK_18;
}
function _setClassMechValue19(uint256 value) internal pure returns(uint256){
require(value < (RARITY_BONUS_MASK_20 / CLASS_MECH_MASK_19));
return value * CLASS_MECH_MASK_19;
}
function _setRarityBonusValue20(uint256 value) internal pure returns(uint256){
require(value < (SPECIALITY_MASK_21 / RARITY_BONUS_MASK_20));
return value * RARITY_BONUS_MASK_20;
}
function _setSpecialityValue21(uint256 value) internal pure returns(uint256){
require(value < (DAMAGE_MASK_22 / SPECIALITY_MASK_21));
return value * SPECIALITY_MASK_21;
}
function _setDamgeValue22(uint256 value) internal pure returns(uint256){
require(value < (AURA_MASK_23 / DAMAGE_MASK_22));
return value * DAMAGE_MASK_22;
}
function _setAuraValue23(uint256 value) internal pure returns(uint256){
require(value < (BASE_MASK_24 / AURA_MASK_23));
return value * AURA_MASK_23;
}
/* WARRIOR IDENTITY GENERATION */
function _computeRunes(uint256 _rarity) internal pure returns (uint256){
return _rarity > UNCOMMON ? _rarity - UNCOMMON : 0;// 1 + _random(0, max, hash, WINGS_MASK_12, RUNES_MASK_11) : 0;
}
function _computeWings(uint256 _rarity, uint256 max, uint256 hash) internal pure returns (uint256){
return _rarity > RARE ? 1 + _random(0, max, hash, PET_MASK_13, WINGS_MASK_12) : 0;
}
function _computePet(uint256 _rarity, uint256 max, uint256 hash) internal pure returns (uint256){
return _rarity > MYTHIC ? 1 + _random(0, max, hash, BORDER_MASK_14, PET_MASK_13) : 0;
}
function _computeBorder(uint256 _rarity) internal pure returns (uint256){
return _rarity >= COMMON ? _rarity - 1 : 0;
}
function _computeBackground(uint256 _rarity) internal pure returns (uint256){
return _rarity;
}
function _unpackPetData(uint256 index) internal pure returns(uint256){
return (PETS_DATA % (1000 ** (index + 1)) / (1000 ** index));
}
function _getPetBonus1(uint256 _pet) internal pure returns(uint256) {
return (_pet % (10 ** (PET_PARAM_1 + 1)) / (10 ** PET_PARAM_1));
}
function _getPetBonus2(uint256 _pet) internal pure returns(uint256) {
return (_pet % (10 ** (PET_PARAM_2 + 1)) / (10 ** PET_PARAM_2));
}
function _getPetAura(uint256 _pet) internal pure returns(uint256) {
return (_pet % (10 ** (PET_AURA + 1)) / (10 ** PET_AURA));
}
function _getBattleBonus(uint256 _setBonusIndex, uint256 _currentBonusIndex, uint256 _petData, uint256 _warriorAuras, uint256 _petAuras) internal pure returns(int256) {
int256 bonus = 0;
if (_setBonusIndex == _currentBonusIndex) {
bonus += int256(BONUS_DATA % (100 ** (_setBonusIndex + 1)) / (100 ** _setBonusIndex)) * PRECISION;
}
//add pet bonuses
if (_setBonusIndex == _getPetBonus1(_petData)) {
bonus += int256(BONUS_DATA % (100 ** (_setBonusIndex + 1)) / (100 ** _setBonusIndex)) * PRECISION / 2;
}
if (_setBonusIndex == _getPetBonus2(_petData)) {
bonus += int256(BONUS_DATA % (100 ** (_setBonusIndex + 1)) / (100 ** _setBonusIndex)) * PRECISION / 2;
}
//add warrior aura bonuses
if (isAuraSet(_warriorAuras, uint8(_setBonusIndex))) {//warriors receive half bonuses from auras
bonus += int256(BONUS_DATA % (100 ** (_setBonusIndex + 1)) / (100 ** _setBonusIndex)) * PRECISION / 2;
}
//add pet aura bonuses
if (isAuraSet(_petAuras, uint8(_setBonusIndex))) {//pets receive full bonues from auras
bonus += int256(BONUS_DATA % (100 ** (_setBonusIndex + 1)) / (100 ** _setBonusIndex)) * PRECISION;
}
return bonus;
}
function _computeRarityBonus(uint256 _rarity, uint256 hash) internal pure returns (uint256){
if (_rarity == UNCOMMON) {
return 1 + _random(0, BONUS_PENETRATION, hash, SPECIALITY_MASK_21, RARITY_BONUS_MASK_20);
}
if (_rarity == RARE) {
return 1 + _random(BONUS_PENETRATION, BONUS_DAMAGE, hash, SPECIALITY_MASK_21, RARITY_BONUS_MASK_20);
}
if (_rarity >= MYTHIC) {
return 1 + _random(0, BONUS_DAMAGE, hash, SPECIALITY_MASK_21, RARITY_BONUS_MASK_20);
}
return BONUS_NONE;
}
function _computeAura(uint256 _rarity, uint256 hash) internal pure returns (uint256){
if (_rarity >= MYTHIC) {
return 1 + _random(0, BONUS_DAMAGE, hash, BASE_MASK_24, AURA_MASK_23);
}
return BONUS_NONE;
}
function _computeRarity(uint256 _reward, uint256 _unique, uint256 _legendary,
uint256 _mythic, uint256 _rare, uint256 _uncommon) internal pure returns(uint256){
uint256 range = _unique + _legendary + _mythic + _rare + _uncommon;
if (_reward >= range) return COMMON; // common
if (_reward >= (range = (range - _uncommon))) return UNCOMMON;
if (_reward >= (range = (range - _rare))) return RARE;
if (_reward >= (range = (range - _mythic))) return MYTHIC;
if (_reward >= (range = (range - _legendary))) return LEGENDARY;
if (_reward < range) return UNIQUE;
return COMMON;
}
function _computeUniqueness(uint256 _rarity, uint256 nextUnique) internal pure returns (uint256){
return _rarity == UNIQUE ? nextUnique : 0;
}
/* identity packing */
/* @returns bonus value which depends on speciality value,
* if speciality == 1 (miner), then bonus value will be equal 4,
* otherwise 1
*/
function _getBonus(uint256 identity) internal pure returns(uint256){
return getSpecialityValue(identity) == MINER_PERK ? 4 : 1;
}
function _computeAndSetBaseParameters16_18_22(uint256 _hash) internal pure returns (uint256, uint256){
uint256 identity = 0;
uint256 damage = 35 + _random(0, 21, _hash, AURA_MASK_23, DAMAGE_MASK_22);
uint256 strength = 45 + _random(0, 26, _hash, CLASS_MECH_MASK_19, STRENGTH_MASK_18);
uint256 agility = 15 + (125 - damage - strength);
uint256 intelligence = 155 - strength - agility - damage;
(strength, agility, intelligence) = _shuffleParams(strength, agility, intelligence, _hash);
identity += _setStrengthValue18(strength);
identity += _setAgilityValue17(agility);
identity += _setIntelligenceValue16(intelligence);
identity += _setDamgeValue22(damage);
uint256 classMech = strength > agility ? (strength > intelligence ? WARRIOR : MAGE) : (agility > intelligence ? ARCHER : MAGE);
return (identity, classMech);
}
function _shuffleParams(uint256 param1, uint256 param2, uint256 param3, uint256 _hash) internal pure returns(uint256, uint256, uint256) {
uint256 temp = param1;
if (_hash % 2 == 0) {
temp = param1;
param1 = param2;
param2 = temp;
}
if ((_hash / 10 % 2) == 0) {
temp = param2;
param2 = param3;
param3 = temp;
}
if ((_hash / 100 % 2) == 0) {
temp = param1;
param1 = param2;
param2 = temp;
}
return (param1, param2, param3);
}
/* RANDOM */
function _random(uint256 _min, uint256 _max, uint256 _hash, uint256 _reminder, uint256 _devider) internal pure returns (uint256){
return ((_hash % _reminder) / _devider) % (_max - _min) + _min;
}
function _random(uint256 _min, uint256 _max, uint256 _hash) internal pure returns (uint256){
return _hash % (_max - _min) + _min;
}
function _getTargetBlock(uint256 _targetBlock) internal view returns(uint256){
uint256 currentBlock = block.number;
uint256 target = currentBlock - (currentBlock % 256) + (_targetBlock % 256);
if (target >= currentBlock) {
return (target - 256);
}
return target;
}
function _getMaxRarityChance() internal pure returns(uint256){
return RARITY_CHANCE_RANGE;
}
function generateWarrior(uint256 _heroIdentity, uint256 _heroLevel, uint256 _targetBlock, uint256 specialPerc, uint32[19] memory params) internal view returns (uint256) {
_targetBlock = _getTargetBlock(_targetBlock);
uint256 identity;
uint256 hash = uint256(keccak256(block.blockhash(_targetBlock), _heroIdentity, block.coinbase, block.difficulty));
//0 _heroLevel produces warriors of COMMON rarity
uint256 rarityChance = _heroLevel == 0 ? RARITY_CHANCE_RANGE :
_random(0, RARITY_CHANCE_RANGE, hash) / (_heroLevel * _getBonus(_heroIdentity)); // 0 - 10 000 000
uint256 rarity = _computeRarity(rarityChance,
params[UNIQUE_INDEX_13],params[LEGENDARY_INDEX_14], params[MYTHIC_INDEX_15], params[RARE_INDEX_16], params[UNCOMMON_INDEX_17]);
uint256 classMech;
// start
(identity, classMech) = _computeAndSetBaseParameters16_18_22(hash);
identity += _setUniqueValue0(_computeUniqueness(rarity, params[UNIQUE_TOTAL_INDEX_18] + 1));
identity += _setRarityValue1(rarity);
identity += _setClassViewValue2(classMech); // 1 to 1 with classMech
identity += _setBodyColorValue3(1 + _random(0, params[BODY_COLOR_MAX_INDEX_0], hash, EYES_MASK_4, BODY_COLOR_MASK_3));
identity += _setEyesValue4(1 + _random(0, params[EYES_MAX_INDEX_1], hash, MOUTH_MASK_5, EYES_MASK_4));
identity += _setMouthValue5(1 + _random(0, params[MOUTH_MAX_2], hash, HEIR_MASK_6, MOUTH_MASK_5));
identity += _setHairValue6(1 + _random(0, params[HAIR_MAX_3], hash, HEIR_COLOR_MASK_7, HEIR_MASK_6));
identity += _setHairColorValue7(1 + _random(0, params[HEIR_COLOR_MAX_4], hash, ARMOR_MASK_8, HEIR_COLOR_MASK_7));
identity += _setArmorValue8(1 + _random(0, params[ARMOR_MAX_5], hash, WEAPON_MASK_9, ARMOR_MASK_8));
identity += _setWeaponValue9(1 + _random(0, params[WEAPON_MAX_6], hash, HAT_MASK_10, WEAPON_MASK_9));
identity += _setHatValue10(_random(0, params[HAT_MAX_7], hash, RUNES_MASK_11, HAT_MASK_10));//removed +1
identity += _setRunesValue11(_computeRunes(rarity));
identity += _setWingsValue12(_computeWings(rarity, params[WINGS_MAX_9], hash));
identity += _setPetValue13(_computePet(rarity, params[PET_MAX_10], hash));
identity += _setBorderValue14(_computeBorder(rarity)); // 1 to 1 with rarity
identity += _setBackgroundValue15(_computeBackground(rarity)); // 1 to 1 with rarity
identity += _setClassMechValue19(classMech);
identity += _setRarityBonusValue20(_computeRarityBonus(rarity, hash));
identity += _setSpecialityValue21(specialPerc); // currently only miner (1)
identity += _setAuraValue23(_computeAura(rarity, hash));
// end
return identity;
}
function _changeParameter(uint256 _paramIndex, uint32 _value, uint32[19] storage parameters) internal {
//we can change only view parameters, and unique count in max range <= 100
require(_paramIndex >= BODY_COLOR_MAX_INDEX_0 && _paramIndex <= UNIQUE_INDEX_13);
//we can NOT set pet, border and background values,
//those values have special logic behind them
require(
_paramIndex != RUNES_MAX_8 &&
_paramIndex != PET_MAX_10 &&
_paramIndex != BORDER_MAX_11 &&
_paramIndex != BACKGROUND_MAX_12
);
//value of bodyColor, eyes, mouth, hair, hairColor, armor, weapon, hat must be < 1000
require(_paramIndex > HAT_MAX_7 || _value < 1000);
//value of wings, must be < 100
require(_paramIndex > BACKGROUND_MAX_12 || _value < 100);
//check that max total number of UNIQUE warriors that we can emit is not > 100
require(_paramIndex != UNIQUE_INDEX_13 || (_value + parameters[UNIQUE_TOTAL_INDEX_18]) <= 100);
parameters[_paramIndex] = _value;
}
function _recordWarriorData(uint256 identity, uint32[19] storage parameters) internal {
uint256 rarity = getRarityValue(identity);
if (rarity == UNCOMMON) { // uncommon
parameters[UNCOMMON_INDEX_17]--;
return;
}
if (rarity == RARE) { // rare
parameters[RARE_INDEX_16]--;
return;
}
if (rarity == MYTHIC) { // mythic
parameters[MYTHIC_INDEX_15]--;
return;
}
if (rarity == LEGENDARY) { // legendary
parameters[LEGENDARY_INDEX_14]--;
return;
}
if (rarity == UNIQUE) { // unique
parameters[UNIQUE_INDEX_13]--;
parameters[UNIQUE_TOTAL_INDEX_18] ++;
return;
}
}
function _validateIdentity(uint256 _identity, uint32[19] memory params) internal pure returns(bool){
uint256 rarity = getRarityValue(_identity);
require(rarity <= UNIQUE);
require(
rarity <= COMMON ||//common
(rarity == UNCOMMON && params[UNCOMMON_INDEX_17] > 0) ||//uncommon
(rarity == RARE && params[RARE_INDEX_16] > 0) ||//rare
(rarity == MYTHIC && params[MYTHIC_INDEX_15] > 0) ||//mythic
(rarity == LEGENDARY && params[LEGENDARY_INDEX_14] > 0) ||//legendary
(rarity == UNIQUE && params[UNIQUE_INDEX_13] > 0)//unique
);
require(rarity != UNIQUE || getUniqueValue(_identity) > params[UNIQUE_TOTAL_INDEX_18]);
//check battle parameters
require(
getStrengthValue(_identity) < 100 &&
getAgilityValue(_identity) < 100 &&
getIntelligenceValue(_identity) < 100 &&
getDamageValue(_identity) <= 55
);
require(getClassMechValue(_identity) <= MAGE);
require(getClassMechValue(_identity) == getClassViewValue(_identity));
require(getSpecialityValue(_identity) <= MINER_PERK);
require(getRarityBonusValue(_identity) <= BONUS_DAMAGE);
require(getAuraValue(_identity) <= BONUS_DAMAGE);
//check view
require(getBodyColorValue(_identity) <= params[BODY_COLOR_MAX_INDEX_0]);
require(getEyesValue(_identity) <= params[EYES_MAX_INDEX_1]);
require(getMouthValue(_identity) <= params[MOUTH_MAX_2]);
require(getHairValue(_identity) <= params[HAIR_MAX_3]);
require(getHairColorValue(_identity) <= params[HEIR_COLOR_MAX_4]);
require(getArmorValue(_identity) <= params[ARMOR_MAX_5]);
require(getWeaponValue(_identity) <= params[WEAPON_MAX_6]);
require(getHatValue(_identity) <= params[HAT_MAX_7]);
require(getRunesValue(_identity) <= params[RUNES_MAX_8]);
require(getWingsValue(_identity) <= params[WINGS_MAX_9]);
require(getPetValue(_identity) <= params[PET_MAX_10]);
require(getBorderValue(_identity) <= params[BORDER_MAX_11]);
require(getBackgroundValue(_identity) <= params[BACKGROUND_MAX_12]);
return true;
}
/* UNPACK METHODS */
//common
function _unpackClassValue(uint256 packedValue) internal pure returns(uint256){
return (packedValue % RARITY_PACK_2 / CLASS_PACK_0);
}
function _unpackRarityBonusValue(uint256 packedValue) internal pure returns(uint256){
return (packedValue % RARITY_PACK_2 / RARITY_BONUS_PACK_1);
}
function _unpackRarityValue(uint256 packedValue) internal pure returns(uint256){
return (packedValue % EXPERIENCE_PACK_3 / RARITY_PACK_2);
}
function _unpackExpValue(uint256 packedValue) internal pure returns(uint256){
return (packedValue % INTELLIGENCE_PACK_4 / EXPERIENCE_PACK_3);
}
function _unpackLevelValue(uint256 packedValue) internal pure returns(uint256){
return (packedValue % INTELLIGENCE_PACK_4) / (EXPERIENCE_PACK_3 * POINTS_TO_LEVEL);
}
function _unpackIntelligenceValue(uint256 packedValue) internal pure returns(int256){
return int256(packedValue % AGILITY_PACK_5 / INTELLIGENCE_PACK_4);
}
function _unpackAgilityValue(uint256 packedValue) internal pure returns(int256){
return int256(packedValue % STRENGTH_PACK_6 / AGILITY_PACK_5);
}
function _unpackStrengthValue(uint256 packedValue) internal pure returns(int256){
return int256(packedValue % BASE_DAMAGE_PACK_7 / STRENGTH_PACK_6);
}
function _unpackBaseDamageValue(uint256 packedValue) internal pure returns(int256){
return int256(packedValue % PET_PACK_8 / BASE_DAMAGE_PACK_7);
}
function _unpackPetValue(uint256 packedValue) internal pure returns(uint256){
return (packedValue % AURA_PACK_9 / PET_PACK_8);
}
function _unpackAuraValue(uint256 packedValue) internal pure returns(uint256){
return (packedValue % WARRIOR_ID_PACK_10 / AURA_PACK_9);
}
//
//pvp unpack
function _unpackIdValue(uint256 packedValue) internal pure returns(uint256){
return (packedValue % PVP_CYCLE_PACK_11 / WARRIOR_ID_PACK_10);
}
function _unpackCycleValue(uint256 packedValue) internal pure returns(uint256){
return (packedValue % RATING_PACK_12 / PVP_CYCLE_PACK_11);
}
function _unpackRatingValue(uint256 packedValue) internal pure returns(uint256){
return (packedValue % PVP_BASE_PACK_13 / RATING_PACK_12);
}
//max cycle skip value cant be more than 1000000000
function _changeCycleValue(uint256 packedValue, uint256 newValue) internal pure returns(uint256){
newValue = newValue > 1000000000 ? 1000000000 : newValue;
return packedValue - (_unpackCycleValue(packedValue) * PVP_CYCLE_PACK_11) + newValue * PVP_CYCLE_PACK_11;
}
function _packWarriorCommonData(uint256 _identity, uint256 _experience) internal pure returns(uint256){
uint256 packedData = 0;
packedData += getClassMechValue(_identity) * CLASS_PACK_0;
packedData += getRarityBonusValue(_identity) * RARITY_BONUS_PACK_1;
packedData += getRarityValue(_identity) * RARITY_PACK_2;
packedData += _experience * EXPERIENCE_PACK_3;
packedData += getIntelligenceValue(_identity) * INTELLIGENCE_PACK_4;
packedData += getAgilityValue(_identity) * AGILITY_PACK_5;
packedData += getStrengthValue(_identity) * STRENGTH_PACK_6;
packedData += getDamageValue(_identity) * BASE_DAMAGE_PACK_7;
packedData += getPetValue(_identity) * PET_PACK_8;
return packedData;
}
function _packWarriorPvpData(uint256 _identity, uint256 _rating, uint256 _pvpCycle, uint256 _warriorId, uint256 _experience) internal pure returns(uint256){
uint256 packedData = _packWarriorCommonData(_identity, _experience);
packedData += _warriorId * WARRIOR_ID_PACK_10;
packedData += _pvpCycle * PVP_CYCLE_PACK_11;
//rating MUST have most significant value!
packedData += _rating * RATING_PACK_12;
return packedData;
}
/* TOURNAMENT BATTLES */
function _packWarriorIds(uint256[] memory packedWarriors) internal pure returns(uint256){
uint256 packedIds = 0;
uint256 length = packedWarriors.length;
for(uint256 i = 0; i < length; i ++) {
packedIds += (MAX_ID_SIZE ** i) * _unpackIdValue(packedWarriors[i]);
}
return packedIds;
}
function _unpackWarriorId(uint256 packedIds, uint256 index) internal pure returns(uint256){
return (packedIds % (MAX_ID_SIZE ** (index + 1)) / (MAX_ID_SIZE ** index));
}
function _packCombinedParams(int256 hp, int256 damage, int256 armor, int256 dodge, int256 penetration) internal pure returns(uint256) {
uint256 combinedWarrior = 0;
combinedWarrior += uint256(hp) * HP_PACK_0;
combinedWarrior += uint256(damage) * DAMAGE_PACK_1;
combinedWarrior += uint256(armor) * ARMOR_PACK_2;
combinedWarrior += uint256(dodge) * DODGE_PACK_3;
combinedWarrior += uint256(penetration) * PENETRATION_PACK_4;
return combinedWarrior;
}
function _unpackProtectionParams(uint256 combinedWarrior) internal pure returns
(int256 hp, int256 armor, int256 dodge){
hp = int256(combinedWarrior % DAMAGE_PACK_1 / HP_PACK_0);
armor = int256(combinedWarrior % DODGE_PACK_3 / ARMOR_PACK_2);
dodge = int256(combinedWarrior % PENETRATION_PACK_4 / DODGE_PACK_3);
}
function _unpackAttackParams(uint256 combinedWarrior) internal pure returns(int256 damage, int256 penetration) {
damage = int256(combinedWarrior % ARMOR_PACK_2 / DAMAGE_PACK_1);
penetration = int256(combinedWarrior % COMBINE_BASE_PACK_5 / PENETRATION_PACK_4);
}
function _combineWarriors(uint256[] memory packedWarriors) internal pure returns (uint256) {
int256 hp;
int256 damage;
int256 armor;
int256 dodge;
int256 penetration;
(hp, damage, armor, dodge, penetration) = _computeCombinedParams(packedWarriors);
return _packCombinedParams(hp, damage, armor, dodge, penetration);
}
function _computeCombinedParams(uint256[] memory packedWarriors) internal pure returns
(int256 totalHp, int256 totalDamage, int256 maxArmor, int256 maxDodge, int256 maxPenetration){
uint256 length = packedWarriors.length;
int256 hp;
int256 armor;
int256 dodge;
int256 penetration;
uint256 warriorAuras;
uint256 petAuras;
(warriorAuras, petAuras) = _getAurasData(packedWarriors);
uint256 packedWarrior;
for(uint256 i = 0; i < length; i ++) {
packedWarrior = packedWarriors[i];
totalDamage += getDamage(packedWarrior, warriorAuras, petAuras);
penetration = getPenetration(packedWarrior, warriorAuras, petAuras);
maxPenetration = maxPenetration > penetration ? maxPenetration : penetration;
(hp, armor, dodge) = _getProtectionParams(packedWarrior, warriorAuras, petAuras);
totalHp += hp;
maxArmor = maxArmor > armor ? maxArmor : armor;
maxDodge = maxDodge > dodge ? maxDodge : dodge;
}
}
function _getAurasData(uint256[] memory packedWarriors) internal pure returns(uint256 warriorAuras, uint256 petAuras) {
uint256 length = packedWarriors.length;
warriorAuras = 0;
petAuras = 0;
uint256 packedWarrior;
for(uint256 i = 0; i < length; i ++) {
packedWarrior = packedWarriors[i];
warriorAuras = enableAura(warriorAuras, (_unpackAuraValue(packedWarrior)));
petAuras = enableAura(petAuras, (_getPetAura(_unpackPetData(_unpackPetValue(packedWarrior)))));
}
warriorAuras = filterWarriorAuras(warriorAuras, petAuras);
return (warriorAuras, petAuras);
}
// Get bit value at position
function isAuraSet(uint256 aura, uint256 auraIndex) internal pure returns (bool) {
return aura & (uint256(0x01) << auraIndex) != 0;
}
// Set bit value at position
function enableAura(uint256 a, uint256 n) internal pure returns (uint256) {
return a | (uint256(0x01) << n);
}
//switch off warrior auras that are enabled in pets auras, pet aura have priority
function filterWarriorAuras(uint256 _warriorAuras, uint256 _petAuras) internal pure returns(uint256) {
return (_warriorAuras & _petAuras) ^ _warriorAuras;
}
function _getTournamentBattles(uint256 _numberOfContenders) internal pure returns(uint256) {
return (_numberOfContenders * BATTLES_PER_CONTENDER / 2);
}
function getTournamentBattleResults(uint256[] memory combinedWarriors, uint256 _targetBlock) internal view returns (uint32[] memory results){
uint256 length = combinedWarriors.length;
results = new uint32[](length);
int256 damage1;
int256 penetration1;
uint256 hash;
uint256 randomIndex;
uint256 exp = 0;
uint256 i;
uint256 result;
for(i = 0; i < length; i ++) {
(damage1, penetration1) = _unpackAttackParams(combinedWarriors[i]);
while(results[i] < BATTLES_PER_CONTENDER_SUM) {
//if we just started generate new random source
//or regenerate if we used all data from it
if (exp == 0 || exp > 73) {
hash = uint256(keccak256(block.blockhash(_getTargetBlock(_targetBlock - i)), uint256(damage1) + now));
exp = 0;
}
//we do not fight with self if there are other warriors
randomIndex = (_random(i + 1 < length ? i + 1 : i, length, hash, 1000 * 10**exp, 10**exp));
result = getTournamentBattleResult(damage1, penetration1, combinedWarriors[i],
combinedWarriors[randomIndex], hash % (1000 * 10**exp) / 10**exp);
results[result == 1 ? i : randomIndex] += 101;//icrement battle count 100 and +1 win
results[result == 1 ? randomIndex : i] += 100;//increment only battle count 100 for loser
if (results[randomIndex] >= BATTLES_PER_CONTENDER_SUM) {
if (randomIndex < length - 1) {
_swapValues(combinedWarriors, results, randomIndex, length - 1);
}
length --;
}
exp++;
}
}
//filter battle count from results
length = combinedWarriors.length;
for(i = 0; i < length; i ++) {
results[i] = results[i] % 100;
}
return results;
}
function _swapValues(uint256[] memory combinedWarriors, uint32[] memory results, uint256 id1, uint256 id2) internal pure {
uint256 temp = combinedWarriors[id1];
combinedWarriors[id1] = combinedWarriors[id2];
combinedWarriors[id2] = temp;
temp = results[id1];
results[id1] = results[id2];
results[id2] = uint32(temp);
}
function getTournamentBattleResult(int256 damage1, int256 penetration1, uint256 combinedWarrior1,
uint256 combinedWarrior2, uint256 randomSource) internal pure returns (uint256)
{
int256 damage2;
int256 penetration2;
(damage2, penetration2) = _unpackAttackParams(combinedWarrior1);
int256 totalHp1 = getCombinedTotalHP(combinedWarrior1, penetration2);
int256 totalHp2 = getCombinedTotalHP(combinedWarrior2, penetration1);
return _getBattleResult(damage1 * getBattleRandom(randomSource, 1) / 100, damage2 * getBattleRandom(randomSource, 10) / 100, totalHp1, totalHp2, randomSource);
}
/* COMMON BATTLE */
function _getBattleResult(int256 damage1, int256 damage2, int256 totalHp1, int256 totalHp2, uint256 randomSource) internal pure returns (uint256){
totalHp1 = (totalHp1 * (PRECISION * PRECISION) / damage2);
totalHp2 = (totalHp2 * (PRECISION * PRECISION) / damage1);
//if draw, let the coin decide who wins
if (totalHp1 == totalHp2) return randomSource % 2 + 1;
return totalHp1 > totalHp2 ? 1 : 2;
}
function getCombinedTotalHP(uint256 combinedData, int256 enemyPenetration) internal pure returns(int256) {
int256 hp;
int256 armor;
int256 dodge;
(hp, armor, dodge) = _unpackProtectionParams(combinedData);
return _getTotalHp(hp, armor, dodge, enemyPenetration);
}
function getTotalHP(uint256 packedData, uint256 warriorAuras, uint256 petAuras, int256 enemyPenetration) internal pure returns(int256) {
int256 hp;
int256 armor;
int256 dodge;
(hp, armor, dodge) = _getProtectionParams(packedData, warriorAuras, petAuras);
return _getTotalHp(hp, armor, dodge, enemyPenetration);
}
function _getTotalHp(int256 hp, int256 armor, int256 dodge, int256 enemyPenetration) internal pure returns(int256) {
int256 piercingResult = (armor - enemyPenetration) < -(75 * PRECISION) ? -(75 * PRECISION) : (armor - enemyPenetration);
int256 mitigation = (PRECISION - piercingResult * PRECISION / (PRECISION + piercingResult / 100) / 100);
return (hp * PRECISION / mitigation + (hp * dodge / (100 * PRECISION)));
}
function _applyLevelBonus(int256 _value, uint256 _level) internal pure returns(int256) {
_level -= 1;
return int256(uint256(_value) * (LEVEL_BONUSES % (100 ** (_level + 1)) / (100 ** _level)) / 10);
}
function _getProtectionParams(uint256 packedData, uint256 warriorAuras, uint256 petAuras) internal pure returns(int256 hp, int256 armor, int256 dodge) {
uint256 rarityBonus = _unpackRarityBonusValue(packedData);
uint256 petData = _unpackPetData(_unpackPetValue(packedData));
int256 strength = _unpackStrengthValue(packedData) * PRECISION + _getBattleBonus(BONUS_STR, rarityBonus, petData, warriorAuras, petAuras);
int256 agility = _unpackAgilityValue(packedData) * PRECISION + _getBattleBonus(BONUS_AGI, rarityBonus, petData, warriorAuras, petAuras);
hp = 100 * PRECISION + strength + 7 * strength / 10 + _getBattleBonus(BONUS_HP, rarityBonus, petData, warriorAuras, petAuras);//add bonus hp
hp = _applyLevelBonus(hp, _unpackLevelValue(packedData));
armor = (strength + 8 * strength / 10 + agility + _getBattleBonus(BONUS_ARMOR, rarityBonus, petData, warriorAuras, petAuras));//add bonus armor
dodge = (2 * agility / 3);
}
function getDamage(uint256 packedWarrior, uint256 warriorAuras, uint256 petAuras) internal pure returns(int256) {
uint256 rarityBonus = _unpackRarityBonusValue(packedWarrior);
uint256 petData = _unpackPetData(_unpackPetValue(packedWarrior));
int256 agility = _unpackAgilityValue(packedWarrior) * PRECISION + _getBattleBonus(BONUS_AGI, rarityBonus, petData, warriorAuras, petAuras);
int256 intelligence = _unpackIntelligenceValue(packedWarrior) * PRECISION + _getBattleBonus(BONUS_INT, rarityBonus, petData, warriorAuras, petAuras);
int256 crit = (agility / 5 + intelligence / 4) + _getBattleBonus(BONUS_CRIT_CHANCE, rarityBonus, petData, warriorAuras, petAuras);
int256 critMultiplier = (PRECISION + intelligence / 25) + _getBattleBonus(BONUS_CRIT_MULT, rarityBonus, petData, warriorAuras, petAuras);
int256 damage = int256(_unpackBaseDamageValue(packedWarrior) * 3 * PRECISION / 2) + _getBattleBonus(BONUS_DAMAGE, rarityBonus, petData, warriorAuras, petAuras);
return (_applyLevelBonus(damage, _unpackLevelValue(packedWarrior)) * (PRECISION + crit * critMultiplier / (100 * PRECISION))) / PRECISION;
}
function getPenetration(uint256 packedWarrior, uint256 warriorAuras, uint256 petAuras) internal pure returns(int256) {
uint256 rarityBonus = _unpackRarityBonusValue(packedWarrior);
uint256 petData = _unpackPetData(_unpackPetValue(packedWarrior));
int256 agility = _unpackAgilityValue(packedWarrior) * PRECISION + _getBattleBonus(BONUS_AGI, rarityBonus, petData, warriorAuras, petAuras);
int256 intelligence = _unpackIntelligenceValue(packedWarrior) * PRECISION + _getBattleBonus(BONUS_INT, rarityBonus, petData, warriorAuras, petAuras);
return (intelligence * 2 + agility + _getBattleBonus(BONUS_PENETRATION, rarityBonus, petData, warriorAuras, petAuras));
}
/* BATTLE PVP */
//@param randomSource must be >= 1000
function getBattleRandom(uint256 randmSource, uint256 _step) internal pure returns(int256){
return int256(100 + _random(0, 11, randmSource, 100 * _step, _step));
}
uint256 internal constant NO_AURA = 0;
function getPVPBattleResult(uint256 packedData1, uint256 packedData2, uint256 randmSource) internal pure returns (uint256){
uint256 petAura1 = _computePVPPetAura(packedData1);
uint256 petAura2 = _computePVPPetAura(packedData2);
uint256 warriorAura1 = _computePVPWarriorAura(packedData1, petAura1);
uint256 warriorAura2 = _computePVPWarriorAura(packedData2, petAura2);
int256 damage1 = getDamage(packedData1, warriorAura1, petAura1) * getBattleRandom(randmSource, 1) / 100;
int256 damage2 = getDamage(packedData2, warriorAura2, petAura2) * getBattleRandom(randmSource, 10) / 100;
int256 totalHp1;
int256 totalHp2;
(totalHp1, totalHp2) = _computeContendersTotalHp(packedData1, warriorAura1, petAura1, packedData2, warriorAura1, petAura1);
return _getBattleResult(damage1, damage2, totalHp1, totalHp2, randmSource);
}
function _computePVPPetAura(uint256 packedData) internal pure returns(uint256) {
return enableAura(NO_AURA, _getPetAura(_unpackPetData(_unpackPetValue(packedData))));
}
function _computePVPWarriorAura(uint256 packedData, uint256 petAuras) internal pure returns(uint256) {
return filterWarriorAuras(enableAura(NO_AURA, _unpackAuraValue(packedData)), petAuras);
}
function _computeContendersTotalHp(uint256 packedData1, uint256 warriorAura1, uint256 petAura1, uint256 packedData2, uint256 warriorAura2, uint256 petAura2)
internal pure returns(int256 totalHp1, int256 totalHp2) {
int256 enemyPenetration = getPenetration(packedData2, warriorAura2, petAura2);
totalHp1 = getTotalHP(packedData1, warriorAura1, petAura1, enemyPenetration);
enemyPenetration = getPenetration(packedData1, warriorAura1, petAura1);
totalHp2 = getTotalHP(packedData2, warriorAura1, petAura1, enemyPenetration);
}
function getRatingRange(uint256 _pvpCycle, uint256 _pvpInterval, uint256 _expandInterval) internal pure returns (uint256){
return 50 + (_pvpCycle * _pvpInterval / _expandInterval * 25);
}
function isMatching(int256 evenRating, int256 oddRating, int256 ratingGap) internal pure returns(bool) {
return evenRating <= (oddRating + ratingGap) && evenRating >= (oddRating - ratingGap);
}
function sort(uint256[] memory data) internal pure {
quickSort(data, int(0), int(data.length - 1));
}
function quickSort(uint256[] memory arr, int256 left, int256 right) internal pure {
int256 i = left;
int256 j = right;
if(i==j) return;
uint256 pivot = arr[uint256(left + (right - left) / 2)];
while (i <= j) {
while (arr[uint256(i)] < pivot) i++;
while (pivot < arr[uint256(j)]) j--;
if (i <= j) {
(arr[uint256(i)], arr[uint256(j)]) = (arr[uint256(j)], arr[uint256(i)]);
i++;
j--;
}
}
if (left < j)
quickSort(arr, left, j);
if (i < right)
quickSort(arr, i, right);
}
function _swapPair(uint256[] memory matchingIds, uint256 id1, uint256 id2, uint256 id3, uint256 id4) internal pure {
uint256 temp = matchingIds[id1];
matchingIds[id1] = matchingIds[id2];
matchingIds[id2] = temp;
temp = matchingIds[id3];
matchingIds[id3] = matchingIds[id4];
matchingIds[id4] = temp;
}
function _swapValues(uint256[] memory matchingIds, uint256 id1, uint256 id2) internal pure {
uint256 temp = matchingIds[id1];
matchingIds[id1] = matchingIds[id2];
matchingIds[id2] = temp;
}
function _getMatchingIds(uint256[] memory matchingIds, uint256 _pvpInterval, uint256 _skipCycles, uint256 _expandInterval)
internal pure returns(uint256 matchingCount)
{
matchingCount = matchingIds.length;
if (matchingCount == 0) return 0;
uint256 warriorId;
uint256 index;
//sort matching ids
quickSort(matchingIds, int256(0), int256(matchingCount - 1));
//find pairs
int256 rating1;
uint256 pairIndex = 0;
int256 ratingRange;
for(index = 0; index < matchingCount; index++) {
//get packed value
warriorId = matchingIds[index];
//unpack rating 1
rating1 = int256(_unpackRatingValue(warriorId));
ratingRange = int256(getRatingRange(_unpackCycleValue(warriorId) + _skipCycles, _pvpInterval, _expandInterval));
if (index > pairIndex && //check left neighbor
isMatching(rating1, int256(_unpackRatingValue(matchingIds[index - 1])), ratingRange)) {
//move matched pairs to the left
//swap pairs
_swapPair(matchingIds, pairIndex, index - 1, pairIndex + 1, index);
//mark last pair position
pairIndex += 2;
} else if (index + 1 < matchingCount && //check right neighbor
isMatching(rating1, int256(_unpackRatingValue(matchingIds[index + 1])), ratingRange)) {
//move matched pairs to the left
//swap pairs
_swapPair(matchingIds, pairIndex, index, pairIndex + 1, index + 1);
//mark last pair position
pairIndex += 2;
//skip next iteration
index++;
}
}
matchingCount = pairIndex;
}
function _getPVPBattleResults(uint256[] memory matchingIds, uint256 matchingCount, uint256 _targetBlock) internal view {
uint256 exp = 0;
uint256 hash = 0;
uint256 result = 0;
for (uint256 even = 0; even < matchingCount; even += 2) {
if (exp == 0 || exp > 73) {
hash = uint256(keccak256(block.blockhash(_getTargetBlock(_targetBlock)), hash));
exp = 0;
}
//compute battle result 1 = even(left) id won, 2 - odd(right) id won
result = getPVPBattleResult(matchingIds[even], matchingIds[even + 1], hash % (1000 * 10**exp) / 10**exp);
require(result > 0 && result < 3);
exp++;
//if odd warrior won, swap his id with even warrior,
//otherwise do nothing,
//even ids are winning ids! odds suck!
if (result == 2) {
_swapValues(matchingIds, even, even + 1);
}
}
}
function _getLevel(uint256 _levelPoints) internal pure returns(uint256) {
return _levelPoints / POINTS_TO_LEVEL;
}
}
contract WarriorGenerator is Ownable, GeneratorInterface {
address coreContract;
/* LIMITS */
uint32[19] public parameters;/* = [
uint32(10),//0_bodyColorMax3
uint32(10),//1_eyeshMax4
uint32(10),//2_mouthMax5
uint32(20),//3_heirMax6
uint32(10),//4_heirColorMax7
uint32(3),//5_armorMax8
uint32(3),//6_weaponMax9
uint32(3),//7_hatMax10
uint32(4),//8_runesMax11
uint32(1),//9_wingsMax12
uint32(10),//10_petMax13
uint32(6),//11_borderMax14
uint32(6),//12_backgroundMax15
uint32(10),//13_unique
uint32(900),//14_legendary
uint32(9000),//15_mythic
uint32(90000),//16_rare
uint32(900000),//17_uncommon
uint32(0)//18_uniqueTotal
];*/
function WarriorGenerator(address _coreContract, uint32[] _settings) public {
uint256 length = _settings.length;
require(length == 18);
require(_settings[8] == 4);//check runes max
require(_settings[10] == 10);//check pets max
require(_settings[11] == 5);//check border max
require(_settings[12] == 6);//check background max
//setup parameters
for(uint256 i = 0; i < length; i ++) {
parameters[i] = _settings[i];
}
coreContract = _coreContract;
}
function changeParameter(uint32 _paramIndex, uint32 _value) external onlyOwner {
CryptoUtils._changeParameter(_paramIndex, _value, parameters);
}
// / @dev simply a boolean to indicate this is the contract we expect to be
function isGenerator() public pure returns (bool){
return true;
}
// / @dev generate new warrior identity
// / @param _heroIdentity Genes of warrior that invoked resurrection, if 0 => Demigod gene that signals to generate unique warrior
// / @param _heroLevel Level of the warrior
// / @_targetBlock block number from which hash will be taken
// / @_perkId special perk id, like MINER(1)
// / @return the identity that are supposed to be passed down to newly arisen warrior
function generateWarrior(uint256 _heroIdentity, uint256 _heroLevel, uint256 _targetBlock, uint256 _perkId)
public returns (uint256)
{
//only core contract can call this method
require(msg.sender == coreContract);
//get memory copy, to reduce storage read requests
uint32[19] memory memoryParams = parameters;
//generate warrior identity
uint256 identity = CryptoUtils.generateWarrior(_heroIdentity, _heroLevel, _targetBlock, _perkId, memoryParams);
//validate before pushing changes to storage
CryptoUtils._validateIdentity(identity, memoryParams);
//push changes to storage
CryptoUtils._recordWarriorData(identity, parameters);
return identity;
}
}
contract AuctionBase {
uint256 public constant PRICE_CHANGE_TIME_STEP = 15 minutes;
struct Auction{
address seller;
uint128 startingPrice;
uint128 endingPrice;
uint64 duration;
uint64 startedAt;
}
mapping (uint256 => Auction) internal tokenIdToAuction;
uint256 public ownerCut;
ERC721 public nonFungibleContract;
event AuctionCreated(uint256 tokenId, address seller, uint256 startingPrice);
event AuctionSuccessful(uint256 tokenId, uint256 totalPrice, address winner, address seller);
event AuctionCancelled(uint256 tokenId, address seller);
function _owns(address _claimant, uint256 _tokenId) internal view returns (bool){
return (nonFungibleContract.ownerOf(_tokenId) == _claimant);
}
function _escrow(address _owner, uint256 _tokenId) internal{
nonFungibleContract.transferFrom(_owner, this, _tokenId);
}
function _transfer(address _receiver, uint256 _tokenId) internal{
nonFungibleContract.transfer(_receiver, _tokenId);
}
function _addAuction(uint256 _tokenId, Auction _auction) internal{
require(_auction.duration >= 1 minutes);
tokenIdToAuction[_tokenId] = _auction;
AuctionCreated(uint256(_tokenId), _auction.seller, _auction.startingPrice);
}
// @dev Cancels an auction unconditionally.
function _cancelAuction(uint256 _tokenId, address _seller) internal{
_removeAuction(_tokenId);
_transfer(_seller, _tokenId);
AuctionCancelled(_tokenId, _seller);
}
function _bid(uint256 _tokenId, uint256 _bidAmount) internal returns (uint256){
Auction storage auction = tokenIdToAuction[_tokenId];
require(_isOnAuction(auction));
uint256 price = _currentPrice(auction);
require(_bidAmount >= price);
address seller = auction.seller;
_removeAuction(_tokenId);
if (price > 0) {
uint256 auctioneerCut = _computeCut(price);
uint256 sellerProceeds = price - auctioneerCut;
seller.transfer(sellerProceeds);
nonFungibleContract.getBeneficiary().transfer(auctioneerCut);
}
uint256 bidExcess = _bidAmount - price;
msg.sender.transfer(bidExcess);
AuctionSuccessful(_tokenId, price, msg.sender, seller);
return price;
}
function _removeAuction(uint256 _tokenId) internal{
delete tokenIdToAuction[_tokenId];
}
function _isOnAuction(Auction storage _auction) internal view returns (bool){
return (_auction.startedAt > 0);
}
function _currentPrice(Auction storage _auction)
internal
view
returns (uint256){
uint256 secondsPassed = 0;
if (now > _auction.startedAt) {
secondsPassed = now - _auction.startedAt;
}
return _computeCurrentPrice(_auction.startingPrice,
_auction.endingPrice,
_auction.duration,
secondsPassed);
}
function _computeCurrentPrice(uint256 _startingPrice,
uint256 _endingPrice,
uint256 _duration,
uint256 _secondsPassed)
internal
pure
returns (uint256){
if (_secondsPassed >= _duration) {
return _endingPrice;
} else {
int256 totalPriceChange = int256(_endingPrice) - int256(_startingPrice);
int256 currentPriceChange = totalPriceChange * int256(_secondsPassed / PRICE_CHANGE_TIME_STEP * PRICE_CHANGE_TIME_STEP) / int256(_duration);
int256 currentPrice = int256(_startingPrice) + currentPriceChange;
return uint256(currentPrice);
}
}
function _computeCut(uint256 _price) internal view returns (uint256){
return _price * ownerCut / 10000;
}
}
contract SaleClockAuction is Pausable, AuctionBase {
bytes4 constant InterfaceSignature_ERC721 = bytes4(0x9f40b779);
bool public isSaleClockAuction = true;
uint256 public minerSaleCount;
uint256[5] public lastMinerSalePrices;
function SaleClockAuction(address _nftAddress, uint256 _cut) public{
require(_cut <= 10000);
ownerCut = _cut;
ERC721 candidateContract = ERC721(_nftAddress);
require(candidateContract.supportsInterface(InterfaceSignature_ERC721));
require(candidateContract.getBeneficiary() != address(0));
nonFungibleContract = candidateContract;
}
function cancelAuction(uint256 _tokenId)
external{
AuctionBase.Auction storage auction = tokenIdToAuction[_tokenId];
require(_isOnAuction(auction));
address seller = auction.seller;
require(msg.sender == seller);
_cancelAuction(_tokenId, seller);
}
function cancelAuctionWhenPaused(uint256 _tokenId)
whenPaused
onlyOwner
external{
AuctionBase.Auction storage auction = tokenIdToAuction[_tokenId];
require(_isOnAuction(auction));
_cancelAuction(_tokenId, auction.seller);
}
function getCurrentPrice(uint256 _tokenId)
external
view
returns (uint256){
AuctionBase.Auction storage auction = tokenIdToAuction[_tokenId];
require(_isOnAuction(auction));
return _currentPrice(auction);
}
function createAuction(uint256 _tokenId,
uint256 _startingPrice,
uint256 _endingPrice,
uint256 _duration,
address _seller)
external{
require(_startingPrice == uint256(uint128(_startingPrice)));
require(_endingPrice == uint256(uint128(_endingPrice)));
require(_duration == uint256(uint64(_duration)));
require(msg.sender == address(nonFungibleContract));
_escrow(_seller, _tokenId);
AuctionBase.Auction memory auction = Auction(_seller,
uint128(_startingPrice),
uint128(_endingPrice),
uint64(_duration),
uint64(now));
_addAuction(_tokenId, auction);
}
function bid(uint256 _tokenId)
external
payable{
address seller = tokenIdToAuction[_tokenId].seller;
uint256 price = _bid(_tokenId, msg.value);
_transfer(msg.sender, _tokenId);
if (seller == nonFungibleContract.getBeneficiary()) {
lastMinerSalePrices[minerSaleCount % 5] = price;
minerSaleCount++;
}
}
function averageMinerSalePrice() external view returns (uint256){
uint256 sum = 0;
for (uint256 i = 0; i < 5; i++){
sum += lastMinerSalePrices[i];
}
return sum / 5;
}
/**getAuctionsById returns packed actions data
* @param tokenIds ids of tokens, whose auction's must be active
* @return auctionData as uint256 array
* @return stepSize number of fields describing auction
*/
function getAuctionsById(uint32[] tokenIds) external view returns(uint256[] memory auctionData, uint32 stepSize) {
stepSize = 6;
auctionData = new uint256[](tokenIds.length * stepSize);
uint32 tokenId;
for(uint32 i = 0; i < tokenIds.length; i ++) {
tokenId = tokenIds[i];
AuctionBase.Auction storage auction = tokenIdToAuction[tokenId];
require(_isOnAuction(auction));
_setTokenData(auctionData, auction, tokenId, i * stepSize);
}
}
/**getAuctions returns packed actions data
* @param fromIndex warrior index from global warrior storage (aka warriorId)
* @param count Number of auction's to find, if count == 0, then exact warriorId(fromIndex) will be searched
* @return auctionData as uint256 array
* @return stepSize number of fields describing auction
*/
function getAuctions(uint32 fromIndex, uint32 count) external view returns(uint256[] memory auctionData, uint32 stepSize) {
stepSize = 6;
if (count == 0) {
AuctionBase.Auction storage auction = tokenIdToAuction[fromIndex];
require(_isOnAuction(auction));
auctionData = new uint256[](1 * stepSize);
_setTokenData(auctionData, auction, fromIndex, count);
return (auctionData, stepSize);
} else {
uint256 totalWarriors = nonFungibleContract.totalSupply();
if (totalWarriors == 0) {
// Return an empty array
return (new uint256[](0), stepSize);
} else {
uint32 totalSize = 0;
uint32 tokenId;
uint32 size = 0;
auctionData = new uint256[](count * stepSize);
for (tokenId = 0; tokenId < totalWarriors && size < count; tokenId++) {
AuctionBase.Auction storage auction1 = tokenIdToAuction[tokenId];
if (_isOnAuction(auction1)) {
totalSize ++;
if (totalSize > fromIndex) {
_setTokenData(auctionData, auction1, tokenId, size++ * stepSize);//warriorId;
}
}
}
if (size < count) {
size *= stepSize;
uint256[] memory repack = new uint256[](size);
for(tokenId = 0; tokenId < size; tokenId++) {
repack[tokenId] = auctionData[tokenId];
}
return (repack, stepSize);
}
return (auctionData, stepSize);
}
}
}
// @dev Returns auction info for an NFT on auction.
// @param _tokenId - ID of NFT on auction.
function getAuction(uint256 _tokenId) external view returns(
address seller,
uint256 startingPrice,
uint256 endingPrice,
uint256 duration,
uint256 startedAt
){
Auction storage auction = tokenIdToAuction[_tokenId];
require(_isOnAuction(auction));
return (auction.seller,
auction.startingPrice,
auction.endingPrice,
auction.duration,
auction.startedAt);
}
//pack NFT data into specified array
function _setTokenData(uint256[] memory auctionData,
AuctionBase.Auction storage auction, uint32 tokenId, uint32 index
) internal view {
auctionData[index] = uint256(tokenId);//0
auctionData[index + 1] = uint256(auction.seller);//1
auctionData[index + 2] = uint256(auction.startingPrice);//2
auctionData[index + 3] = uint256(auction.endingPrice);//3
auctionData[index + 4] = uint256(auction.duration);//4
auctionData[index + 5] = uint256(auction.startedAt);//5
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"constant":false,"inputs":[{"name":"_pveBattleFee","type":"uint256"}],"name":"setPVEBattleFee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_levelPoints","type":"uint256"}],"name":"getPVEDuration","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"_newBank","type":"address"}],"name":"setBank","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_warriorId","type":"uint32"}],"name":"pvpContenderRemoved","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"packedContenders","type":"uint256[]"}],"name":"tournamentFinished","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_warriorIds","type":"uint32[]"}],"name":"getWarriorOwners","outputs":[{"name":"owners","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MINER_AUCTION_DURATION","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_warriorId","type":"uint32"}],"name":"finishPVE","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"}],"name":"setGeneratorAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"uint256"}],"name":"getWarrior","outputs":[{"name":"identity","type":"uint256"},{"name":"cooldownEndBlock","type":"uint256"},{"name":"level","type":"uint256"},{"name":"rating","type":"uint256"},{"name":"action","type":"uint256"},{"name":"dungeonIndex","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"indexFrom","type":"uint32"},{"name":"count","type":"uint32"}],"name":"getWarriorsFromIndex","outputs":[{"name":"warriorsData","type":"uint256[]"},{"name":"stepSize","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_warriorId","type":"uint256"},{"name":"_startingPrice","type":"uint256"},{"name":"_endingPrice","type":"uint256"},{"name":"_duration","type":"uint256"}],"name":"createSaleAuction","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_warriorIds","type":"uint32[]"}],"name":"getWarriors","outputs":[{"name":"warriorsData","type":"uint256[]"},{"name":"stepSize","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"}],"name":"setBattleProviderAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"PVP_BATTLE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"IDLE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newIssuer","type":"address"}],"name":"setIssuer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"battleProvider","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBeneficiary","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"secs","type":"uint256"}],"name":"setSecondsPerBlock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"dungeonRequirements","outputs":[{"name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_warriorId","type":"uint256"}],"name":"startPVE","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"name":"owner","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"newContractAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"TOURNAMENT_BATTLE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"}],"name":"setSaleAuctionAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"minerCreatedCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"count","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_v2Address","type":"address"}],"name":"setNewAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MINER_STARTING_PRICE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bankAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"secondsPerBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"generator","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"warriorToApproved","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"tokensOfOwner","outputs":[{"name":"ownerTokens","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_levelPoints","type":"uint256"}],"name":"getPVECooldown","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pveBattleFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"warriorToOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_warriorId","type":"uint32"}],"name":"signUpForPVP","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"MINER_CREATION_LIMIT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_LEVEL","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"issuerAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_tokenId","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_warriorIds","type":"uint32[]"}],"name":"finishPVEBatch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"createMinerAuction","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"warriorsData","type":"uint256[]"},{"name":"matchingCount","type":"uint256"}],"name":"pvpFinished","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"isPVPListener","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"saleAuction","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PVE_COMPENSATION","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_warriorIds","type":"uint32[]"}],"name":"signUpForTournament","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"MINER_END_PRICE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PVE_BATTLE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"POINTS_TO_LEVEL","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"adminAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"dungeonIndex","type":"uint256"},{"indexed":false,"name":"warriorId","type":"uint256"},{"indexed":false,"name":"battleEndBlock","type":"uint256"}],"name":"PVEStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"dungeonIndex","type":"uint256"},{"indexed":false,"name":"warriorId","type":"uint256"},{"indexed":false,"name":"cooldownEndBlock","type":"uint256"},{"indexed":false,"name":"rewardId","type":"uint256"}],"name":"PVEFinished","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"from","type":"address"},{"indexed":false,"name":"to","type":"address"},{"indexed":false,"name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"approved","type":"address"},{"indexed":false,"name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"warriorId","type":"uint256"},{"indexed":false,"name":"identity","type":"uint256"}],"name":"Arise","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newContract","type":"address"}],"name":"ContractUpgrade","type":"event"}]Contract Creation Code
606060409081526003805460a060020a60ff021916905560c090519081016040908152600a8252601e6020830152603c90820152606460608201526096608082015260fa60a082015262000058906004906006620000d4565b50600f600555662386f26fc10000600b5534156200007557600080fd5b6003805460018054600160a060020a033316600160a060020a0319918216811790925560a060020a60ff02199092167401000000000000000000000000000000000000000017821681179092556002805490911690911790556200019e565b600183019183908215620001655791602002820160005b838211156200013157835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302620000eb565b8015620001635782816101000a81549063ffffffff021916905560040160208160030104928301926001030262000131565b505b506200017392915062000177565b5090565b6200019b91905b808211156200017357805463ffffffff191681556001016200017e565b90565b6139a680620001ae6000396000f3006060604052600436106102db5763ffffffff60e060020a6000350416623ead5f81146102e257806301ffc9a7146102f857806306fdde03146103445780630763b78b146103ce578063090d23b9146103f6578063095ea7b3146104155780630b9835cf1461043757806311196cc21461045357806316922822146104a257806318160ddd146105135780631c088897146105265780631dfa63291461053957806323b872dd1461055557806325a02ff61461057d57806329372ad01461059c5780632c90d20d146105eb5780633d7d3f5a1461066d5780633f4ba83a1461068c578063407299ba1461069f57806340a4437e146106bd57806345d6c9db146106dc5780635478786c146106ef57806355cc4e57146107025780635604af4914610721578063565a2e2c146107505780635663896e146107635780635b229ae4146107795780635c975abb146107a85780635f689fed146107bb5780636352211e146107c65780636af04a57146107dc5780636ed84231146107ef5780636fbde40d14610802578063704b6c0214610821578063709eaa931461084057806370a082311461085357806371587988146108725780637637da03146108915780637822ed49146108a45780637a7d4937146108b75780637afa1eed146108ca57806382bd5a71146108dd5780638456cb59146108f35780638462151c146109065780638aabff061461092557806395d89b411461093b5780639610f0e61461094e57806396b01c3714610961578063994ebbe3146109775780639a49eab514610988578063a49062d41461099b578063a63234e0146109ae578063a9059cbb146109c1578063b949f2f3146109e3578063cef6a39a14610a01578063dfba3be114610a14578063e4d9d21214610a65578063e6cbe35114610a78578063f105e23b14610a8b578063f693de1d14610a9e578063f6ea625214610ae2578063f80d9e5814610af5578063f94f691014610b08578063fc6f946814610b1b575b600080fd5b005b34156102ed57600080fd5b6102e0600435610b2e565b341561030357600080fd5b6103307fffffffff0000000000000000000000000000000000000000000000000000000060043516610b61565b604051901515815260200160405180910390f35b341561034f57600080fd5b610357610db6565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561039357808201518382015260200161037b565b50505050905090810190601f1680156103c05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156103d957600080fd5b6103e4600435610ded565b60405190815260200160405180910390f35b341561040157600080fd5b6102e0600160a060020a0360043516610e02565b341561042057600080fd5b6102e0600160a060020a0360043516602435610e54565b341561044257600080fd5b6102e063ffffffff60043516610f1a565b341561045e57600080fd5b6102e06004602481358181019083013580602081810201604051908101604052809392919081815260200183836020028082843750949650610f9295505050505050565b34156104ad57600080fd5b6104c06004803560248101910135610fb9565b60405160208082528190810183818151815260200191508051906020019060200280838360005b838110156104ff5780820151838201526020016104e7565b505050509050019250505060405180910390f35b341561051e57600080fd5b6103e461105e565b341561053157600080fd5b6103e4611065565b341561054457600080fd5b6102e063ffffffff6004351661106c565b341561056057600080fd5b6102e0600160a060020a036004358116906024351660443561113c565b341561058857600080fd5b6102e0600160a060020a03600435166111ff565b34156105a757600080fd5b6105b26004356112ae565b60405180878152602001868152602001858152602001848152602001838152602001828152602001965050505050505060405180910390f35b34156105f657600080fd5b61060d63ffffffff60043581169060243516611332565b60405163ffffffff8216602082015260408082528190810184818151815260200191508051906020019060200280838360005b83811015610658578082015183820152602001610640565b50505050905001935050505060405180910390f35b341561067857600080fd5b6102e06004356024356044356064356113f0565b341561069757600080fd5b6102e06114f8565b34156106aa57600080fd5b61060d6004803560248101910135611590565b34156106c857600080fd5b6102e0600160a060020a0360043516611630565b34156106e757600080fd5b6103e46116df565b34156106fa57600080fd5b6103e46116e4565b341561070d57600080fd5b6102e0600160a060020a03600435166116e9565b341561072c57600080fd5b61073461173b565b604051600160a060020a03909116815260200160405180910390f35b341561075b57600080fd5b61073461174a565b341561076e57600080fd5b6102e0600435611759565b341561078457600080fd5b61078f6004356117ad565b60405163ffffffff909116815260200160405180910390f35b34156107b357600080fd5b6103306117da565b6102e06004356117ea565b34156107d157600080fd5b610734600435611963565b34156107e757600080fd5b610734611987565b34156107fa57600080fd5b6103e4611996565b341561080d57600080fd5b6102e0600160a060020a036004351661199b565b341561082c57600080fd5b6102e0600160a060020a0360043516611a4a565b341561084b57600080fd5b6103e4611ab7565b341561085e57600080fd5b6103e4600160a060020a0360043516611abd565b341561087d57600080fd5b6102e0600160a060020a0360043516611ad8565b341561089c57600080fd5b6103e4611b66565b34156108af57600080fd5b610734611b72565b34156108c257600080fd5b6103e4611b81565b34156108d557600080fd5b610734611b87565b34156108e857600080fd5b610734600435611b96565b34156108fe57600080fd5b6102e0611bb1565b341561091157600080fd5b6104c0600160a060020a0360043516611c3d565b341561093057600080fd5b6103e4600435611d1f565b341561094657600080fd5b610357611d4e565b341561095957600080fd5b6103e4611d85565b341561096c57600080fd5b610734600435611d8b565b6102e063ffffffff60043516611da6565b341561099357600080fd5b6103e4611f17565b34156109a657600080fd5b6103e4611f1d565b34156109b957600080fd5b610734611f22565b34156109cc57600080fd5b6102e0600160a060020a0360043516602435611f31565b34156109ee57600080fd5b6102e06004803560248101910135611ff5565b3415610a0c57600080fd5b6102e061218c565b3415610a1f57600080fd5b6102e06004602481358181019083013580602081810201604051908101604052809392919081815260200183836020028082843750949650509335935061232b92505050565b3415610a7057600080fd5b610330612350565b3415610a8357600080fd5b610734612355565b3415610a9657600080fd5b6103e4612364565b6102e0600460248135818101908301358060208181020160405190810160405280939291908181526020018383602002808284375094965061236f95505050505050565b3415610aed57600080fd5b6103e46124c2565b3415610b0057600080fd5b6103e46124cd565b3415610b1357600080fd5b6103e46124d2565b3415610b2657600080fd5b6107346124d7565b60015433600160a060020a03908116911614610b4957600080fd5b66071afd498d00008111610b5c57600080fd5b600b55565b60006040517f737570706f727473496e7465726661636528627974657334290000000000000081526019016040518091039020600160e060020a03191682600160e060020a0319161480610dae57506040517f746f6b656e734f664f776e657228616464726573732900000000000000000000815260160160405180910390206040517f7472616e7366657246726f6d28616464726573732c616464726573732c75696e81527f7432353629000000000000000000000000000000000000000000000000000000602082015260250160405180910390206040517f7472616e7366657228616464726573732c75696e743235362900000000000000815260190160405180910390206040517f617070726f766528616464726573732c75696e74323536290000000000000000815260180160405180910390206040517f6f776e65724f662875696e743235362900000000000000000000000000000000815260100160405180910390206040517f62616c616e63654f662861646472657373290000000000000000000000000000815260120160405180910390206040517f746f74616c537570706c792829000000000000000000000000000000000000008152600d0160405180910390206040517f73796d626f6c2829000000000000000000000000000000000000000000000000815260080160405180910390206040517f6e616d6528290000000000000000000000000000000000000000000000000000815260060160405180910390201818181818181818600160e060020a03191682600160e060020a031916145b90505b919050565b60408051908101604052600e81527f43727970746f57617272696f7273000000000000000000000000000000000000602082015281565b6000610384610dfb836124e6565b0292915050565b60025433600160a060020a03908116911614610e1d57600080fd5b600160a060020a0381161515610e3257600080fd5b60028054600160a060020a031916600160a060020a0392909216919091179055565b60035460a060020a900460ff1615610e6b57600080fd5b610e7533826124f3565b1515610e8057600080fd5b6000600682815481101515610e9157fe5b600091825260209091206002909102016001015460c060020a900463ffffffff1614610ebc57600080fd5b610ec68183612513565b7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925338383604051600160a060020a039384168152919092166020820152604080820192909252606001905180910390a15050565b600d5460009033600160a060020a03908116911614610f3857600080fd5b6006805463ffffffff8416908110610f4c57fe5b60009182526020909120600291820201600181015490925060c060020a900463ffffffff1614610f7b57600080fd5b600101805460c060020a63ffffffff021916905550565b600d5433600160a060020a03908116911614610fad57600080fd5b610fb681612541565b50565b610fc16138eb565b81600081604051805910610fd25750595b90808252806020026020018201604052509250600090505b81811015611056576007600086868481811061100257fe5b6020908102929092013563ffffffff1683525081019190915260400160002054600160a060020a031683828151811061103757fe5b600160a060020a03909216602092830290910190910152600101610fea565b505092915050565b6006545b90565b6201518081565b60035460009060a060020a900460ff161561108657600080fd5b6006805463ffffffff841690811061109a57fe5b60009182526020909120600290910201805490915015156110ba57600080fd5b60018181015460c060020a900463ffffffff16146110d757600080fd5b600181015467ffffffffffffffff438116911611156110f557600080fd5b6111048263ffffffff1661257b565b600160a060020a033316600066071afd498d0000604051600060405180830381858888f19350505050151561113857600080fd5b5050565b60035460a060020a900460ff161561115357600080fd5b600160a060020a038216151561116857600080fd5b30600160a060020a031682600160a060020a03161415151561118957600080fd5b611193338261271d565b151561119e57600080fd5b6111a883826124f3565b15156111b357600080fd5b60006006828154811015156111c457fe5b600091825260209091206002909102016001015460c060020a900463ffffffff16146111ef57600080fd5b6111fa83838361273d565b505050565b60015460009033600160a060020a0390811691161461121d57600080fd5b5080600160a060020a03811663c3f0dad96000604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b151561126557600080fd5b6102c65a03f1151561127657600080fd5b50505060405180519050151561128b57600080fd5b600c8054600160a060020a031916600160a060020a039290921691909117905550565b60008060008060008060006006888154811015156112c857fe5b600091825260209091206002909102018054600190910154909967ffffffffffffffff8083169a50680100000000000000008304169850608060020a8204600790810b900b975063ffffffff60c060020a83048116975060e060020a909204909116945092505050565b61133a6138eb565b60068054600090819063ffffffff80871690881690910310156113685760065463ffffffff87169003611370565b8463ffffffff165b91508263ffffffff1682026040518059106113885750595b90808252806020026020018201604052509350600090505b818163ffffffff1610156113e7576113df84600683890163ffffffff168154811015156113c957fe5b9060005260206000209060020201858402612813565b6001016113a0565b50509250929050565b60035460a060020a900460ff161561140757600080fd5b6114113385612933565b151561141c57600080fd5b600060068581548110151561142d57fe5b600091825260209091206002909102016001015460c060020a900463ffffffff161461145857600080fd5b600a5461146f908590600160a060020a0316612513565b600a54600160a060020a03166327ebe40a858585853360405160e060020a63ffffffff88160281526004810195909552602485019390935260448401919091526064830152600160a060020a0316608482015260a401600060405180830381600087803b15156114de57600080fd5b6102c65a03f115156114ef57600080fd5b50505050505050565b60015433600160a060020a0390811691161461151357600080fd5b60035460a060020a900460ff16151561152b57600080fd5b600a54600160a060020a0316151561154257600080fd5b600c54600160a060020a0316151561155957600080fd5b600d54600160a060020a0316151561157057600080fd5b600054600160a060020a03161561158657600080fd5b61158e612978565b565b6115986138eb565b600660008382026040518059106115ac5750595b90808252806020026020018201604052509250600090505b63ffffffff81168490101561162857611620836006878763ffffffff86168181106115eb57fe5b9050602002013563ffffffff1663ffffffff1681548110151561160a57fe5b9060005260206000209060020201848402612813565b6001016115c4565b509250929050565b60015460009033600160a060020a0390811691161461164e57600080fd5b5080600160a060020a03811663f773ab806000604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b151561169657600080fd5b6102c65a03f115156116a757600080fd5b5050506040518051905015156116bc57600080fd5b600d8054600160a060020a031916600160a060020a039290921691909117905550565b600281565b600081565b60015433600160a060020a0390811691161461170457600080fd5b600160a060020a038116151561171957600080fd5b60038054600160a060020a031916600160a060020a0392909216919091179055565b600d54600160a060020a031681565b600254600160a060020a031690565b60035433600160a060020a0390811691161480611784575060015433600160a060020a039081169116145b8061179d575060025433600160a060020a039081169116145b15156117a857600080fd5b600555565b600481600681106117ba57fe5b60089182820401919006600402915054906101000a900463ffffffff1681565b60035460a060020a900460ff1681565b600354600090819060a060020a900460ff161561180657600080fd5b600b5434101561181557600080fd5b61181f3384612933565b151561182a57600080fd5b600680548490811061183857fe5b600091825260209091206002909102018054909250151561185857600080fd5b6118d58260c060405190810160409081528254825260019092015467ffffffffffffffff80821660208401526801000000000000000082041692820192909252608060020a8204600790810b810b900b606082015263ffffffff60c060020a83048116608083015260e060020a90920490911660a08201526129cb565b15156118e057600080fd5b6118e983612a55565b50600b543403600160a060020a03331681156108fc0282604051600060405180830381858888f19350505050151561192057600080fd5b600254600b54600160a060020a039091169066071afd498cffff190180156108fc0290604051600060405180830381858888f1935050505015156111fa57600080fd5b600081815260076020526040902054600160a060020a0316801515610db157600080fd5b600054600160a060020a031681565b600381565b60015460009033600160a060020a039081169116146119b957600080fd5b5080600160a060020a0381166385b861886000604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b1515611a0157600080fd5b6102c65a03f11515611a1257600080fd5b505050604051805190501515611a2757600080fd5b600a8054600160a060020a031916600160a060020a039290921691909117905550565b60015433600160a060020a0390811691161480611a75575060025433600160a060020a039081169116145b1515611a8057600080fd5b600160a060020a0381161515611a9557600080fd5b60018054600160a060020a031916600160a060020a0392909216919091179055565b600e5481565b600160a060020a031660009081526008602052604090205490565b60015433600160a060020a03908116911614611af357600080fd5b60035460a060020a900460ff161515611b0b57600080fd5b60008054600160a060020a031916600160a060020a0383161790557f450db8da6efbe9c22f2347f7c2021231df1fc58d3ae9a2fa75d39fa44619930581604051600160a060020a03909116815260200160405180910390a150565b67016345785d8a000081565b600254600160a060020a031681565b60055481565b600c54600160a060020a031681565b600960205260009081526040902054600160a060020a031681565b60035433600160a060020a0390811691161480611bdc575060015433600160a060020a039081169116145b80611bf5575060025433600160a060020a039081169116145b1515611c0057600080fd5b60035460a060020a900460ff1615611c1757600080fd5b6003805474ff0000000000000000000000000000000000000000191660a060020a179055565b611c456138eb565b6000611c4f6138eb565b6000806000611c5d87611abd565b9450841515611c8d576000604051805910611c755750595b90808252806020026020018201604052509550611d15565b84604051805910611c9b5750595b90808252806020026020018201604052509350611cb661105e565b925060009150600090505b82811015611d1157600081815260076020526040902054600160a060020a0388811691161415611d095780848381518110611cf857fe5b602090810290910101526001909101905b600101611cc1565b8395505b5050505050919050565b600080611d2b836124e6565b905060198110611d4057621275009150611d48565b80610e100291505b50919050565b60408051908101604052600281527f4357000000000000000000000000000000000000000000000000000000000000602082015281565b600b5481565b600760205260009081526040902054600160a060020a031681565b6003546000908190819060a060020a900460ff1615611dc457600080fd5b611dd4338563ffffffff16612933565b1515611ddf57600080fd5b6006805463ffffffff8616908110611df357fe5b6000918252602090912060029091020180549093501515611e1357600080fd5b600183015460c060020a900463ffffffff1615611e2f57600080fd5b600d546001840154600160a060020a039091169063637492259068010000000000000000900467ffffffffffffffff1660006040516020015260405160e060020a63ffffffff841602815267ffffffffffffffff9091166004820152602401602060405180830381600087803b1515611ea757600080fd5b6102c65a03f11515611eb857600080fd5b50505060405180519250503482901015611ed157600080fd5b611edb8483612b6d565b5034819003600160a060020a03331681156108fc0282604051600060405180830381858888f193505050501515611f1157600080fd5b50505050565b610b4081565b601981565b600354600160a060020a031681565b60035460a060020a900460ff1615611f4857600080fd5b600160a060020a0382161515611f5d57600080fd5b30600160a060020a031682600160a060020a031614151515611f7e57600080fd5b600a54600160a060020a0383811691161415611f9957600080fd5b611fa333826124f3565b1515611fae57600080fd5b6000600682815481101515611fbf57fe5b600091825260209091206002909102016001015460c060020a900463ffffffff1614611fea57600080fd5b61113833838361273d565b60035460009081908190819060a060020a900460ff161561201557600080fd5b849350601484111561202657600080fd5b43925061205f86868080602002602001604051908101604052809392919081815260200183836020028082843750612c4a945050505050565b151561206a57600080fd5b600091505b8382101561210a57600686868481811061208557fe5b9050602002013563ffffffff1663ffffffff168154811015156120a457fe5b9060005260206000209060020201905080600001546000141580156120d9575060018181015460c060020a900463ffffffff16145b80156120f45750600181015467ffffffffffffffff16839011155b15156120ff57600080fd5b60019091019061206f565b600091505b838210156121495761213e86868481811061212657fe5b9050602002013563ffffffff1663ffffffff1661257b565b60019091019061210f565b600160a060020a03331666071afd498d0000850280156108fc0290604051600060405180830381858888f19350505050151561218457600080fd5b505050505050565b600354600090819033600160a060020a039081169116146121ac57600080fd5b600e54610b4090106121bd57600080fd5b600e8054600190810191829055600c54600160a060020a031691639729ec2691600090600019430190826040516020015260405160e060020a63ffffffff87160281526004810194909452602484019290925260448301526064820152608401602060405180830381600087803b151561223657600080fd5b6102c65a03f1151561224757600080fd5b505050604051805160025490935061226c91508390600160a060020a03166000612cd7565b600a54909150612286908290600160a060020a0316612513565b600a54600160a060020a03166327ebe40a826122a0612ea3565b60025466b1a2bc2ec50000906201518090600160a060020a031660405160e060020a63ffffffff88160281526004810195909552602485019390935260448401919091526064830152600160a060020a0316608482015260a401600060405180830381600087803b151561231357600080fd5b6102c65a03f1151561232457600080fd5b5050505050565b600d5433600160a060020a0390811691161461234657600080fd5b6111388282612f54565b600190565b600a54600160a060020a031681565b66071afd498d000081565b600d5460009081908190600160a060020a03166324abfc0282604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b15156123bd57600080fd5b6102c65a03f115156123ce57600080fd5b505050604051805193505034839010156123e757600080fd5b60058451146123f557600080fd5b6123ff3385612fa7565b151561240a57600080fd5b61241384612c4a565b151561241e57600080fd5b600091505b60058210156124825761246c600685848151811061243d57fe5b9060200190602002015163ffffffff1681548110151561245957fe5b9060005260206000209060020201613004565b151561247757600080fd5b600190910190612423565b61248c8484613044565b5034829003600160a060020a03331681156108fc0282604051600060405180830381858888f193505050501515611f1157600080fd5b66b1a2bc2ec5000081565b600181565b600a81565b600154600160a060020a031681565b6000600a825b0492915050565b600090815260076020526040902054600160a060020a0391821691161490565b6000918252600960205260409091208054600160a060020a031916600160a060020a03909216919091179055565b60008082519150600090505b818110156111fa5761257383828151811061256457fe5b90602001906020020151613191565b60010161254d565b60008060008060068581548110151561259057fe5b6000918252602090912060029091020160018101805460c060020a63ffffffff0219169055600554815491955043916125c8906131f6565b60018701546125ec9068010000000000000000900467ffffffffffffffff16611d1f565b8115156125f557fe5b048115156125ff57fe5b60018701805467ffffffffffffffff1916929091049290920167ffffffffffffffff16179081905560e060020a900463ffffffff169250600683101561266e576001848101805463ffffffff60e060020a808304821690940116909202600160e060020a039092169190911790555b600085815260076020526040902054600160a060020a03169150612692828561321b565b60018501549091507f28391d64a7259a49ae308a9637b1bc7c9598bc70986c1be7dc76bfeca776eeb69083908590889067ffffffffffffffff1685604051600160a060020a03909516855263ffffffff909316602085015260408085019290925267ffffffffffffffff166060840152608083019190915260a0909101905180910390a15050505050565b600090815260096020526040902054600160a060020a0391821691161490565b600160a060020a03808316600081815260086020908152604080832080546001019055858352600790915290208054600160a060020a03191690911790558316156127be57600160a060020a03831660009081526008602090815260408083208054600019019055838352600990915290208054600160a060020a03191690555b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef838383604051600160a060020a039384168152919092166020820152604080820192909252606001905180910390a1505050565b81548363ffffffff83168151811061282757fe5b6020908102909101015260018083015467ffffffffffffffff1690849063ffffffff908401168151811061285757fe5b60209081029091010152600182015467ffffffffffffffff68010000000000000000909104168363ffffffff60028401168151811061289257fe5b602090810290910101526001820154608060020a9004600790810b900b8363ffffffff6003840116815181106128c457fe5b60209081029091010152600182015463ffffffff60c060020a90910481169084906004840116815181106128f457fe5b60209081029091010152600182015463ffffffff60e060020a909104811690849060058401168151811061292457fe5b60209081029091010152505050565b600081815260076020526040812054600160a060020a0384811691161480156129715750600082815260096020526040902054600160a060020a0316155b9392505050565b60015433600160a060020a0390811691161461299357600080fd5b60035460a060020a900460ff1615156129ab57600080fd5b6003805474ff000000000000000000000000000000000000000019169055565b600080826080015163ffffffff161480156129fe57504367ffffffffffffffff16826020015167ffffffffffffffff1611155b8015610dae575060048260a0015163ffffffff1660068110612a1c57fe5b600891828204019190066004029054906101000a900463ffffffff1663ffffffff16826040015167ffffffffffffffff16101592915050565b6000600682815481101515612a6657fe5b600091825260209091206001600290920201908101805460c060020a63ffffffff02191660c060020a1790819055600554919250439190612abd9067ffffffffffffffff6801000000000000000090910416610ded565b811515612ac657fe5b60018401805467ffffffffffffffff9390920493909301821667ffffffffffffffff1990911617918290557f2beb437cab0f7996c35525f60a5f33b31a35ffa1cd1222de87fabc22dc22df8191339163ffffffff60e060020a83041691869116604051600160a060020a03909416845263ffffffff909216602084015260408084019190915267ffffffffffffffff90911660608301526080909101905180910390a15050565b60008060068463ffffffff16815481101515612b8557fe5b90600052602060002090600202019150612ba58463ffffffff168361330f565b600d54909150600160a060020a031663a99306e784338460405160e060020a63ffffffff8616028152600160a060020a03909216600483015260248201526044016000604051808303818588803b1515612bfe57600080fd5b6125ee5a03f11515612c0f57600080fd5b50505050600191909101805460c060020a63ffffffff0219167802000000000000000000000000000000000000000000000000179055505050565b60008060008084519250600090505b82811015612cca578060010191505b82821015612cc257848281518110612c7c57fe5b9060200190602002015163ffffffff16858281518110612c9857fe5b9060200190602002015163ffffffff161415612cb75760009350612ccf565b600190910190612c68565b600101612c59565b600193505b505050919050565b6000612ce16138fd565b600060c0604051908101604090815287825267ffffffffffffffff86166020830152600a908201526064606082015260006080820181905260a082015260068054919350600191808301612d358382613932565b6000928352602090922085916002020181518155602082015160018201805467ffffffffffffffff191667ffffffffffffffff9290921691909117905560408201518160010160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060608201518160010160106101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555060808201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060a08201516001919091018054600160e060020a031660e060020a63ffffffff938416021790559290910392505081168114612e3557600080fd5b7f45c2f8b44389d131c5935d84d0d684b2e2ed61f439b17258ca08abaf935762a38582886040518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a1612e9a6000868361273d565b95945050505050565b600a5460009081908190600160a060020a0316639b311b1782604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b1515612ef157600080fd5b6102c65a03f11515612f0257600080fd5b50505060405180519250506fffffffffffffffffffffffffffffffff82168214612f2b57600080fd5b506002600382020467016345785d8a0000811015612f4e575067016345785d8a00005b92915050565b60005b818110156111fa57612f85612f80848381518110612f7157fe5b9060200190602002015161334b565b613371565b612f9f612f9a848360010181518110612f7157fe5b613451565b600201612f57565b600080600083519150600090505b81811015612ff957612fe285858381518110612fcd57fe5b9060200190602002015163ffffffff16612933565b1515612ff15760009250611056565b600101612fb5565b506001949350505050565b600181015460009060326801000000000000000090910467ffffffffffffffff1610801590610dae5750506001015460c060020a900463ffffffff161590565b61304c6138eb565b600061305784613591565b9150600090505b60058110156130d4576003600685838151811061307757fe5b9060200190602002015163ffffffff1681548110151561309357fe5b6000918252602090912060016002909202018101805463ffffffff9390931660c060020a0260c060020a63ffffffff0219909316929092179091550161305e565b600d54600160a060020a031663f8b608a18433856040518463ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561315257808201518382015260200161313a565b5050505090500193505050506000604051808303818588803b151561317657600080fd5b6125ee5a03f1151561318757600080fd5b5050505050505050565b60005b600581101561113857600060066131ab8484613635565b815481106131b557fe5b6000918252602090912060016002909202018101805463ffffffff9390931660c060020a0260c060020a63ffffffff02199093169290921790915501613194565b6000600161320383613666565b1461320f576001613212565b60045b60ff1692915050565b600c54815460018301546000928392600160a060020a0390911691639729ec26919061325c9068010000000000000000900467ffffffffffffffff166124e6565b600187015467ffffffffffffffff16600019016000806040516020015260405160e060020a63ffffffff87160281526004810194909452602484019290925267ffffffffffffffff1660448301526064820152608401602060405180830381600087803b15156132cb57600080fd5b6102c65a03f115156132dc57600080fd5b5050506040518051905090506133078185600554600c610e10028115156132ff57fe5b044301612cd7565b949350505050565b8054600182015460009161297191608060020a8104600790810b900b908490879068010000000000000000900467ffffffffffffffff1661369d565b600068056bc75e2d631000006c0c9f2c9cd04674edea40000000835b068115156124ec57fe5b60008060068381548110151561338357fe5b60009182526020909120600290910201600181015490925068010000000000000000900467ffffffffffffffff16905060fa8110156133fb57600a0160fa81116133cd57806133d0565b60fa5b8260010160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b50600101805460c060020a63ffffffff0219608060020a808304600790810b608201900b67ffffffffffffffff160277ffffffffffffffff00000000000000000000000000000000199092169190911716905550565b60008060008060068581548110151561346657fe5b60009182526020909120600290910201600181015490945068010000000000000000900467ffffffffffffffff16925082915060fa8210156134de576001840180546fffffffffffffffff000000000000000019166801000000000000000060059490940167ffffffffffffffff8116949094021790555b6134e7836124e6565b6134f0836124e6565b116134fd57601d19613500565b60465b6001850154608060020a9004600790810b900b019050600081121561352657600061353d565b633b9aca008113613537578061353d565b633b9aca005b6001909401805460c060020a63ffffffff021960079690960b67ffffffffffffffff16608060020a0277ffffffffffffffff0000000000000000000000000000000019909116179490941690935550505050565b6135996138eb565b60008060056040518059106135ab5750595b90808252806020026020018201604052509250600090505b600581101561362e578381815181106135d857fe5b9060200190602002015163ffffffff169150613610826006848154811015156135fd57fe5b906000526020600020906002020161330f565b83828151811061361c57fe5b602090810290910101526001016135c3565b5050919050565b6000816402540be4000a826001016402540be4000a8481151561365457fe5b0681151561365e57fe5b049392505050565b6000751aba4714957d300d0e549208b31adb1000000000000076010b46c6cdd6e3e0828f4db456ff0c8ea000000000000083613367565b6000806136aa87846136f1565b701d6329f1c35ca4bfabb9f561000000000087026c0c9f2c9cd04674edea40000000870268056bc75e2d631000008702909201919091010191508190505095945050505050565b60008060016136ff85613781565b0201600a61370c856137b4565b020161271061371a856137e9565b0201620186a08302016305f5e100613731856137f8565b02016402540be40061374285613827565b020164e8d4a5100061375385613858565b0201655af3107a40006137658561388a565b0201662386f26fc10000613778856138c2565b02019392505050565b600073af298d050e4395d69670b12b7f410000000000007406d79f82328ea3da61e066ebb2f88a00000000000083613367565b60007406d79f82328ea3da61e066ebb2f88a000000000000751aba4714957d300d0e549208b31adb1000000000000083613367565b6000612710620186a083613367565b6000710b7abc627050305adf14a3d9e4000000000072047bf19673df52e37f2410011d10000000000083613367565b600072047bf19673df52e37f2410011d1000000000007301c06a5ec5433c60ddaa16406f5a40000000000083613367565b60007301c06a5ec5433c60ddaa16406f5a40000000000073af298d050e4395d69670b12b7f4100000000000083613367565b600076010b46c6cdd6e3e0828f4db456ff0c8ea0000000000000766867a5a867f103b2fffa5a71fba0e7b68000000000000083613367565b60006ec097ce7bc90715b34b9f10000000006f4b3b4ca85a86c47a098a22400000000083613367565b60206040519081016040526000815290565b60c06040519081016040908152600080835260208301819052908201819052606082018190526080820181905260a082015290565b8154818355818115116111fa576000838152602090206111fa916110629160029182028101918502015b80821115613976576000808255600182015560020161395c565b50905600a165627a7a72305820c68b552b70bc95684b1c4fa9f9cf52e9806fbbf5e2141b9124f61d0fd229c0150029
Deployed Bytecode
0x6060604052600436106102db5763ffffffff60e060020a6000350416623ead5f81146102e257806301ffc9a7146102f857806306fdde03146103445780630763b78b146103ce578063090d23b9146103f6578063095ea7b3146104155780630b9835cf1461043757806311196cc21461045357806316922822146104a257806318160ddd146105135780631c088897146105265780631dfa63291461053957806323b872dd1461055557806325a02ff61461057d57806329372ad01461059c5780632c90d20d146105eb5780633d7d3f5a1461066d5780633f4ba83a1461068c578063407299ba1461069f57806340a4437e146106bd57806345d6c9db146106dc5780635478786c146106ef57806355cc4e57146107025780635604af4914610721578063565a2e2c146107505780635663896e146107635780635b229ae4146107795780635c975abb146107a85780635f689fed146107bb5780636352211e146107c65780636af04a57146107dc5780636ed84231146107ef5780636fbde40d14610802578063704b6c0214610821578063709eaa931461084057806370a082311461085357806371587988146108725780637637da03146108915780637822ed49146108a45780637a7d4937146108b75780637afa1eed146108ca57806382bd5a71146108dd5780638456cb59146108f35780638462151c146109065780638aabff061461092557806395d89b411461093b5780639610f0e61461094e57806396b01c3714610961578063994ebbe3146109775780639a49eab514610988578063a49062d41461099b578063a63234e0146109ae578063a9059cbb146109c1578063b949f2f3146109e3578063cef6a39a14610a01578063dfba3be114610a14578063e4d9d21214610a65578063e6cbe35114610a78578063f105e23b14610a8b578063f693de1d14610a9e578063f6ea625214610ae2578063f80d9e5814610af5578063f94f691014610b08578063fc6f946814610b1b575b600080fd5b005b34156102ed57600080fd5b6102e0600435610b2e565b341561030357600080fd5b6103307fffffffff0000000000000000000000000000000000000000000000000000000060043516610b61565b604051901515815260200160405180910390f35b341561034f57600080fd5b610357610db6565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561039357808201518382015260200161037b565b50505050905090810190601f1680156103c05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156103d957600080fd5b6103e4600435610ded565b60405190815260200160405180910390f35b341561040157600080fd5b6102e0600160a060020a0360043516610e02565b341561042057600080fd5b6102e0600160a060020a0360043516602435610e54565b341561044257600080fd5b6102e063ffffffff60043516610f1a565b341561045e57600080fd5b6102e06004602481358181019083013580602081810201604051908101604052809392919081815260200183836020028082843750949650610f9295505050505050565b34156104ad57600080fd5b6104c06004803560248101910135610fb9565b60405160208082528190810183818151815260200191508051906020019060200280838360005b838110156104ff5780820151838201526020016104e7565b505050509050019250505060405180910390f35b341561051e57600080fd5b6103e461105e565b341561053157600080fd5b6103e4611065565b341561054457600080fd5b6102e063ffffffff6004351661106c565b341561056057600080fd5b6102e0600160a060020a036004358116906024351660443561113c565b341561058857600080fd5b6102e0600160a060020a03600435166111ff565b34156105a757600080fd5b6105b26004356112ae565b60405180878152602001868152602001858152602001848152602001838152602001828152602001965050505050505060405180910390f35b34156105f657600080fd5b61060d63ffffffff60043581169060243516611332565b60405163ffffffff8216602082015260408082528190810184818151815260200191508051906020019060200280838360005b83811015610658578082015183820152602001610640565b50505050905001935050505060405180910390f35b341561067857600080fd5b6102e06004356024356044356064356113f0565b341561069757600080fd5b6102e06114f8565b34156106aa57600080fd5b61060d6004803560248101910135611590565b34156106c857600080fd5b6102e0600160a060020a0360043516611630565b34156106e757600080fd5b6103e46116df565b34156106fa57600080fd5b6103e46116e4565b341561070d57600080fd5b6102e0600160a060020a03600435166116e9565b341561072c57600080fd5b61073461173b565b604051600160a060020a03909116815260200160405180910390f35b341561075b57600080fd5b61073461174a565b341561076e57600080fd5b6102e0600435611759565b341561078457600080fd5b61078f6004356117ad565b60405163ffffffff909116815260200160405180910390f35b34156107b357600080fd5b6103306117da565b6102e06004356117ea565b34156107d157600080fd5b610734600435611963565b34156107e757600080fd5b610734611987565b34156107fa57600080fd5b6103e4611996565b341561080d57600080fd5b6102e0600160a060020a036004351661199b565b341561082c57600080fd5b6102e0600160a060020a0360043516611a4a565b341561084b57600080fd5b6103e4611ab7565b341561085e57600080fd5b6103e4600160a060020a0360043516611abd565b341561087d57600080fd5b6102e0600160a060020a0360043516611ad8565b341561089c57600080fd5b6103e4611b66565b34156108af57600080fd5b610734611b72565b34156108c257600080fd5b6103e4611b81565b34156108d557600080fd5b610734611b87565b34156108e857600080fd5b610734600435611b96565b34156108fe57600080fd5b6102e0611bb1565b341561091157600080fd5b6104c0600160a060020a0360043516611c3d565b341561093057600080fd5b6103e4600435611d1f565b341561094657600080fd5b610357611d4e565b341561095957600080fd5b6103e4611d85565b341561096c57600080fd5b610734600435611d8b565b6102e063ffffffff60043516611da6565b341561099357600080fd5b6103e4611f17565b34156109a657600080fd5b6103e4611f1d565b34156109b957600080fd5b610734611f22565b34156109cc57600080fd5b6102e0600160a060020a0360043516602435611f31565b34156109ee57600080fd5b6102e06004803560248101910135611ff5565b3415610a0c57600080fd5b6102e061218c565b3415610a1f57600080fd5b6102e06004602481358181019083013580602081810201604051908101604052809392919081815260200183836020028082843750949650509335935061232b92505050565b3415610a7057600080fd5b610330612350565b3415610a8357600080fd5b610734612355565b3415610a9657600080fd5b6103e4612364565b6102e0600460248135818101908301358060208181020160405190810160405280939291908181526020018383602002808284375094965061236f95505050505050565b3415610aed57600080fd5b6103e46124c2565b3415610b0057600080fd5b6103e46124cd565b3415610b1357600080fd5b6103e46124d2565b3415610b2657600080fd5b6107346124d7565b60015433600160a060020a03908116911614610b4957600080fd5b66071afd498d00008111610b5c57600080fd5b600b55565b60006040517f737570706f727473496e7465726661636528627974657334290000000000000081526019016040518091039020600160e060020a03191682600160e060020a0319161480610dae57506040517f746f6b656e734f664f776e657228616464726573732900000000000000000000815260160160405180910390206040517f7472616e7366657246726f6d28616464726573732c616464726573732c75696e81527f7432353629000000000000000000000000000000000000000000000000000000602082015260250160405180910390206040517f7472616e7366657228616464726573732c75696e743235362900000000000000815260190160405180910390206040517f617070726f766528616464726573732c75696e74323536290000000000000000815260180160405180910390206040517f6f776e65724f662875696e743235362900000000000000000000000000000000815260100160405180910390206040517f62616c616e63654f662861646472657373290000000000000000000000000000815260120160405180910390206040517f746f74616c537570706c792829000000000000000000000000000000000000008152600d0160405180910390206040517f73796d626f6c2829000000000000000000000000000000000000000000000000815260080160405180910390206040517f6e616d6528290000000000000000000000000000000000000000000000000000815260060160405180910390201818181818181818600160e060020a03191682600160e060020a031916145b90505b919050565b60408051908101604052600e81527f43727970746f57617272696f7273000000000000000000000000000000000000602082015281565b6000610384610dfb836124e6565b0292915050565b60025433600160a060020a03908116911614610e1d57600080fd5b600160a060020a0381161515610e3257600080fd5b60028054600160a060020a031916600160a060020a0392909216919091179055565b60035460a060020a900460ff1615610e6b57600080fd5b610e7533826124f3565b1515610e8057600080fd5b6000600682815481101515610e9157fe5b600091825260209091206002909102016001015460c060020a900463ffffffff1614610ebc57600080fd5b610ec68183612513565b7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925338383604051600160a060020a039384168152919092166020820152604080820192909252606001905180910390a15050565b600d5460009033600160a060020a03908116911614610f3857600080fd5b6006805463ffffffff8416908110610f4c57fe5b60009182526020909120600291820201600181015490925060c060020a900463ffffffff1614610f7b57600080fd5b600101805460c060020a63ffffffff021916905550565b600d5433600160a060020a03908116911614610fad57600080fd5b610fb681612541565b50565b610fc16138eb565b81600081604051805910610fd25750595b90808252806020026020018201604052509250600090505b81811015611056576007600086868481811061100257fe5b6020908102929092013563ffffffff1683525081019190915260400160002054600160a060020a031683828151811061103757fe5b600160a060020a03909216602092830290910190910152600101610fea565b505092915050565b6006545b90565b6201518081565b60035460009060a060020a900460ff161561108657600080fd5b6006805463ffffffff841690811061109a57fe5b60009182526020909120600290910201805490915015156110ba57600080fd5b60018181015460c060020a900463ffffffff16146110d757600080fd5b600181015467ffffffffffffffff438116911611156110f557600080fd5b6111048263ffffffff1661257b565b600160a060020a033316600066071afd498d0000604051600060405180830381858888f19350505050151561113857600080fd5b5050565b60035460a060020a900460ff161561115357600080fd5b600160a060020a038216151561116857600080fd5b30600160a060020a031682600160a060020a03161415151561118957600080fd5b611193338261271d565b151561119e57600080fd5b6111a883826124f3565b15156111b357600080fd5b60006006828154811015156111c457fe5b600091825260209091206002909102016001015460c060020a900463ffffffff16146111ef57600080fd5b6111fa83838361273d565b505050565b60015460009033600160a060020a0390811691161461121d57600080fd5b5080600160a060020a03811663c3f0dad96000604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b151561126557600080fd5b6102c65a03f1151561127657600080fd5b50505060405180519050151561128b57600080fd5b600c8054600160a060020a031916600160a060020a039290921691909117905550565b60008060008060008060006006888154811015156112c857fe5b600091825260209091206002909102018054600190910154909967ffffffffffffffff8083169a50680100000000000000008304169850608060020a8204600790810b900b975063ffffffff60c060020a83048116975060e060020a909204909116945092505050565b61133a6138eb565b60068054600090819063ffffffff80871690881690910310156113685760065463ffffffff87169003611370565b8463ffffffff165b91508263ffffffff1682026040518059106113885750595b90808252806020026020018201604052509350600090505b818163ffffffff1610156113e7576113df84600683890163ffffffff168154811015156113c957fe5b9060005260206000209060020201858402612813565b6001016113a0565b50509250929050565b60035460a060020a900460ff161561140757600080fd5b6114113385612933565b151561141c57600080fd5b600060068581548110151561142d57fe5b600091825260209091206002909102016001015460c060020a900463ffffffff161461145857600080fd5b600a5461146f908590600160a060020a0316612513565b600a54600160a060020a03166327ebe40a858585853360405160e060020a63ffffffff88160281526004810195909552602485019390935260448401919091526064830152600160a060020a0316608482015260a401600060405180830381600087803b15156114de57600080fd5b6102c65a03f115156114ef57600080fd5b50505050505050565b60015433600160a060020a0390811691161461151357600080fd5b60035460a060020a900460ff16151561152b57600080fd5b600a54600160a060020a0316151561154257600080fd5b600c54600160a060020a0316151561155957600080fd5b600d54600160a060020a0316151561157057600080fd5b600054600160a060020a03161561158657600080fd5b61158e612978565b565b6115986138eb565b600660008382026040518059106115ac5750595b90808252806020026020018201604052509250600090505b63ffffffff81168490101561162857611620836006878763ffffffff86168181106115eb57fe5b9050602002013563ffffffff1663ffffffff1681548110151561160a57fe5b9060005260206000209060020201848402612813565b6001016115c4565b509250929050565b60015460009033600160a060020a0390811691161461164e57600080fd5b5080600160a060020a03811663f773ab806000604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b151561169657600080fd5b6102c65a03f115156116a757600080fd5b5050506040518051905015156116bc57600080fd5b600d8054600160a060020a031916600160a060020a039290921691909117905550565b600281565b600081565b60015433600160a060020a0390811691161461170457600080fd5b600160a060020a038116151561171957600080fd5b60038054600160a060020a031916600160a060020a0392909216919091179055565b600d54600160a060020a031681565b600254600160a060020a031690565b60035433600160a060020a0390811691161480611784575060015433600160a060020a039081169116145b8061179d575060025433600160a060020a039081169116145b15156117a857600080fd5b600555565b600481600681106117ba57fe5b60089182820401919006600402915054906101000a900463ffffffff1681565b60035460a060020a900460ff1681565b600354600090819060a060020a900460ff161561180657600080fd5b600b5434101561181557600080fd5b61181f3384612933565b151561182a57600080fd5b600680548490811061183857fe5b600091825260209091206002909102018054909250151561185857600080fd5b6118d58260c060405190810160409081528254825260019092015467ffffffffffffffff80821660208401526801000000000000000082041692820192909252608060020a8204600790810b810b900b606082015263ffffffff60c060020a83048116608083015260e060020a90920490911660a08201526129cb565b15156118e057600080fd5b6118e983612a55565b50600b543403600160a060020a03331681156108fc0282604051600060405180830381858888f19350505050151561192057600080fd5b600254600b54600160a060020a039091169066071afd498cffff190180156108fc0290604051600060405180830381858888f1935050505015156111fa57600080fd5b600081815260076020526040902054600160a060020a0316801515610db157600080fd5b600054600160a060020a031681565b600381565b60015460009033600160a060020a039081169116146119b957600080fd5b5080600160a060020a0381166385b861886000604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b1515611a0157600080fd5b6102c65a03f11515611a1257600080fd5b505050604051805190501515611a2757600080fd5b600a8054600160a060020a031916600160a060020a039290921691909117905550565b60015433600160a060020a0390811691161480611a75575060025433600160a060020a039081169116145b1515611a8057600080fd5b600160a060020a0381161515611a9557600080fd5b60018054600160a060020a031916600160a060020a0392909216919091179055565b600e5481565b600160a060020a031660009081526008602052604090205490565b60015433600160a060020a03908116911614611af357600080fd5b60035460a060020a900460ff161515611b0b57600080fd5b60008054600160a060020a031916600160a060020a0383161790557f450db8da6efbe9c22f2347f7c2021231df1fc58d3ae9a2fa75d39fa44619930581604051600160a060020a03909116815260200160405180910390a150565b67016345785d8a000081565b600254600160a060020a031681565b60055481565b600c54600160a060020a031681565b600960205260009081526040902054600160a060020a031681565b60035433600160a060020a0390811691161480611bdc575060015433600160a060020a039081169116145b80611bf5575060025433600160a060020a039081169116145b1515611c0057600080fd5b60035460a060020a900460ff1615611c1757600080fd5b6003805474ff0000000000000000000000000000000000000000191660a060020a179055565b611c456138eb565b6000611c4f6138eb565b6000806000611c5d87611abd565b9450841515611c8d576000604051805910611c755750595b90808252806020026020018201604052509550611d15565b84604051805910611c9b5750595b90808252806020026020018201604052509350611cb661105e565b925060009150600090505b82811015611d1157600081815260076020526040902054600160a060020a0388811691161415611d095780848381518110611cf857fe5b602090810290910101526001909101905b600101611cc1565b8395505b5050505050919050565b600080611d2b836124e6565b905060198110611d4057621275009150611d48565b80610e100291505b50919050565b60408051908101604052600281527f4357000000000000000000000000000000000000000000000000000000000000602082015281565b600b5481565b600760205260009081526040902054600160a060020a031681565b6003546000908190819060a060020a900460ff1615611dc457600080fd5b611dd4338563ffffffff16612933565b1515611ddf57600080fd5b6006805463ffffffff8616908110611df357fe5b6000918252602090912060029091020180549093501515611e1357600080fd5b600183015460c060020a900463ffffffff1615611e2f57600080fd5b600d546001840154600160a060020a039091169063637492259068010000000000000000900467ffffffffffffffff1660006040516020015260405160e060020a63ffffffff841602815267ffffffffffffffff9091166004820152602401602060405180830381600087803b1515611ea757600080fd5b6102c65a03f11515611eb857600080fd5b50505060405180519250503482901015611ed157600080fd5b611edb8483612b6d565b5034819003600160a060020a03331681156108fc0282604051600060405180830381858888f193505050501515611f1157600080fd5b50505050565b610b4081565b601981565b600354600160a060020a031681565b60035460a060020a900460ff1615611f4857600080fd5b600160a060020a0382161515611f5d57600080fd5b30600160a060020a031682600160a060020a031614151515611f7e57600080fd5b600a54600160a060020a0383811691161415611f9957600080fd5b611fa333826124f3565b1515611fae57600080fd5b6000600682815481101515611fbf57fe5b600091825260209091206002909102016001015460c060020a900463ffffffff1614611fea57600080fd5b61113833838361273d565b60035460009081908190819060a060020a900460ff161561201557600080fd5b849350601484111561202657600080fd5b43925061205f86868080602002602001604051908101604052809392919081815260200183836020028082843750612c4a945050505050565b151561206a57600080fd5b600091505b8382101561210a57600686868481811061208557fe5b9050602002013563ffffffff1663ffffffff168154811015156120a457fe5b9060005260206000209060020201905080600001546000141580156120d9575060018181015460c060020a900463ffffffff16145b80156120f45750600181015467ffffffffffffffff16839011155b15156120ff57600080fd5b60019091019061206f565b600091505b838210156121495761213e86868481811061212657fe5b9050602002013563ffffffff1663ffffffff1661257b565b60019091019061210f565b600160a060020a03331666071afd498d0000850280156108fc0290604051600060405180830381858888f19350505050151561218457600080fd5b505050505050565b600354600090819033600160a060020a039081169116146121ac57600080fd5b600e54610b4090106121bd57600080fd5b600e8054600190810191829055600c54600160a060020a031691639729ec2691600090600019430190826040516020015260405160e060020a63ffffffff87160281526004810194909452602484019290925260448301526064820152608401602060405180830381600087803b151561223657600080fd5b6102c65a03f1151561224757600080fd5b505050604051805160025490935061226c91508390600160a060020a03166000612cd7565b600a54909150612286908290600160a060020a0316612513565b600a54600160a060020a03166327ebe40a826122a0612ea3565b60025466b1a2bc2ec50000906201518090600160a060020a031660405160e060020a63ffffffff88160281526004810195909552602485019390935260448401919091526064830152600160a060020a0316608482015260a401600060405180830381600087803b151561231357600080fd5b6102c65a03f1151561232457600080fd5b5050505050565b600d5433600160a060020a0390811691161461234657600080fd5b6111388282612f54565b600190565b600a54600160a060020a031681565b66071afd498d000081565b600d5460009081908190600160a060020a03166324abfc0282604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b15156123bd57600080fd5b6102c65a03f115156123ce57600080fd5b505050604051805193505034839010156123e757600080fd5b60058451146123f557600080fd5b6123ff3385612fa7565b151561240a57600080fd5b61241384612c4a565b151561241e57600080fd5b600091505b60058210156124825761246c600685848151811061243d57fe5b9060200190602002015163ffffffff1681548110151561245957fe5b9060005260206000209060020201613004565b151561247757600080fd5b600190910190612423565b61248c8484613044565b5034829003600160a060020a03331681156108fc0282604051600060405180830381858888f193505050501515611f1157600080fd5b66b1a2bc2ec5000081565b600181565b600a81565b600154600160a060020a031681565b6000600a825b0492915050565b600090815260076020526040902054600160a060020a0391821691161490565b6000918252600960205260409091208054600160a060020a031916600160a060020a03909216919091179055565b60008082519150600090505b818110156111fa5761257383828151811061256457fe5b90602001906020020151613191565b60010161254d565b60008060008060068581548110151561259057fe5b6000918252602090912060029091020160018101805460c060020a63ffffffff0219169055600554815491955043916125c8906131f6565b60018701546125ec9068010000000000000000900467ffffffffffffffff16611d1f565b8115156125f557fe5b048115156125ff57fe5b60018701805467ffffffffffffffff1916929091049290920167ffffffffffffffff16179081905560e060020a900463ffffffff169250600683101561266e576001848101805463ffffffff60e060020a808304821690940116909202600160e060020a039092169190911790555b600085815260076020526040902054600160a060020a03169150612692828561321b565b60018501549091507f28391d64a7259a49ae308a9637b1bc7c9598bc70986c1be7dc76bfeca776eeb69083908590889067ffffffffffffffff1685604051600160a060020a03909516855263ffffffff909316602085015260408085019290925267ffffffffffffffff166060840152608083019190915260a0909101905180910390a15050505050565b600090815260096020526040902054600160a060020a0391821691161490565b600160a060020a03808316600081815260086020908152604080832080546001019055858352600790915290208054600160a060020a03191690911790558316156127be57600160a060020a03831660009081526008602090815260408083208054600019019055838352600990915290208054600160a060020a03191690555b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef838383604051600160a060020a039384168152919092166020820152604080820192909252606001905180910390a1505050565b81548363ffffffff83168151811061282757fe5b6020908102909101015260018083015467ffffffffffffffff1690849063ffffffff908401168151811061285757fe5b60209081029091010152600182015467ffffffffffffffff68010000000000000000909104168363ffffffff60028401168151811061289257fe5b602090810290910101526001820154608060020a9004600790810b900b8363ffffffff6003840116815181106128c457fe5b60209081029091010152600182015463ffffffff60c060020a90910481169084906004840116815181106128f457fe5b60209081029091010152600182015463ffffffff60e060020a909104811690849060058401168151811061292457fe5b60209081029091010152505050565b600081815260076020526040812054600160a060020a0384811691161480156129715750600082815260096020526040902054600160a060020a0316155b9392505050565b60015433600160a060020a0390811691161461299357600080fd5b60035460a060020a900460ff1615156129ab57600080fd5b6003805474ff000000000000000000000000000000000000000019169055565b600080826080015163ffffffff161480156129fe57504367ffffffffffffffff16826020015167ffffffffffffffff1611155b8015610dae575060048260a0015163ffffffff1660068110612a1c57fe5b600891828204019190066004029054906101000a900463ffffffff1663ffffffff16826040015167ffffffffffffffff16101592915050565b6000600682815481101515612a6657fe5b600091825260209091206001600290920201908101805460c060020a63ffffffff02191660c060020a1790819055600554919250439190612abd9067ffffffffffffffff6801000000000000000090910416610ded565b811515612ac657fe5b60018401805467ffffffffffffffff9390920493909301821667ffffffffffffffff1990911617918290557f2beb437cab0f7996c35525f60a5f33b31a35ffa1cd1222de87fabc22dc22df8191339163ffffffff60e060020a83041691869116604051600160a060020a03909416845263ffffffff909216602084015260408084019190915267ffffffffffffffff90911660608301526080909101905180910390a15050565b60008060068463ffffffff16815481101515612b8557fe5b90600052602060002090600202019150612ba58463ffffffff168361330f565b600d54909150600160a060020a031663a99306e784338460405160e060020a63ffffffff8616028152600160a060020a03909216600483015260248201526044016000604051808303818588803b1515612bfe57600080fd5b6125ee5a03f11515612c0f57600080fd5b50505050600191909101805460c060020a63ffffffff0219167802000000000000000000000000000000000000000000000000179055505050565b60008060008084519250600090505b82811015612cca578060010191505b82821015612cc257848281518110612c7c57fe5b9060200190602002015163ffffffff16858281518110612c9857fe5b9060200190602002015163ffffffff161415612cb75760009350612ccf565b600190910190612c68565b600101612c59565b600193505b505050919050565b6000612ce16138fd565b600060c0604051908101604090815287825267ffffffffffffffff86166020830152600a908201526064606082015260006080820181905260a082015260068054919350600191808301612d358382613932565b6000928352602090922085916002020181518155602082015160018201805467ffffffffffffffff191667ffffffffffffffff9290921691909117905560408201518160010160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060608201518160010160106101000a81548167ffffffffffffffff021916908360070b67ffffffffffffffff16021790555060808201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060a08201516001919091018054600160e060020a031660e060020a63ffffffff938416021790559290910392505081168114612e3557600080fd5b7f45c2f8b44389d131c5935d84d0d684b2e2ed61f439b17258ca08abaf935762a38582886040518084600160a060020a0316600160a060020a03168152602001838152602001828152602001935050505060405180910390a1612e9a6000868361273d565b95945050505050565b600a5460009081908190600160a060020a0316639b311b1782604051602001526040518163ffffffff1660e060020a028152600401602060405180830381600087803b1515612ef157600080fd5b6102c65a03f11515612f0257600080fd5b50505060405180519250506fffffffffffffffffffffffffffffffff82168214612f2b57600080fd5b506002600382020467016345785d8a0000811015612f4e575067016345785d8a00005b92915050565b60005b818110156111fa57612f85612f80848381518110612f7157fe5b9060200190602002015161334b565b613371565b612f9f612f9a848360010181518110612f7157fe5b613451565b600201612f57565b600080600083519150600090505b81811015612ff957612fe285858381518110612fcd57fe5b9060200190602002015163ffffffff16612933565b1515612ff15760009250611056565b600101612fb5565b506001949350505050565b600181015460009060326801000000000000000090910467ffffffffffffffff1610801590610dae5750506001015460c060020a900463ffffffff161590565b61304c6138eb565b600061305784613591565b9150600090505b60058110156130d4576003600685838151811061307757fe5b9060200190602002015163ffffffff1681548110151561309357fe5b6000918252602090912060016002909202018101805463ffffffff9390931660c060020a0260c060020a63ffffffff0219909316929092179091550161305e565b600d54600160a060020a031663f8b608a18433856040518463ffffffff1660e060020a0281526004018083600160a060020a0316600160a060020a0316815260200180602001828103825283818151815260200191508051906020019060200280838360005b8381101561315257808201518382015260200161313a565b5050505090500193505050506000604051808303818588803b151561317657600080fd5b6125ee5a03f1151561318757600080fd5b5050505050505050565b60005b600581101561113857600060066131ab8484613635565b815481106131b557fe5b6000918252602090912060016002909202018101805463ffffffff9390931660c060020a0260c060020a63ffffffff02199093169290921790915501613194565b6000600161320383613666565b1461320f576001613212565b60045b60ff1692915050565b600c54815460018301546000928392600160a060020a0390911691639729ec26919061325c9068010000000000000000900467ffffffffffffffff166124e6565b600187015467ffffffffffffffff16600019016000806040516020015260405160e060020a63ffffffff87160281526004810194909452602484019290925267ffffffffffffffff1660448301526064820152608401602060405180830381600087803b15156132cb57600080fd5b6102c65a03f115156132dc57600080fd5b5050506040518051905090506133078185600554600c610e10028115156132ff57fe5b044301612cd7565b949350505050565b8054600182015460009161297191608060020a8104600790810b900b908490879068010000000000000000900467ffffffffffffffff1661369d565b600068056bc75e2d631000006c0c9f2c9cd04674edea40000000835b068115156124ec57fe5b60008060068381548110151561338357fe5b60009182526020909120600290910201600181015490925068010000000000000000900467ffffffffffffffff16905060fa8110156133fb57600a0160fa81116133cd57806133d0565b60fa5b8260010160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b50600101805460c060020a63ffffffff0219608060020a808304600790810b608201900b67ffffffffffffffff160277ffffffffffffffff00000000000000000000000000000000199092169190911716905550565b60008060008060068581548110151561346657fe5b60009182526020909120600290910201600181015490945068010000000000000000900467ffffffffffffffff16925082915060fa8210156134de576001840180546fffffffffffffffff000000000000000019166801000000000000000060059490940167ffffffffffffffff8116949094021790555b6134e7836124e6565b6134f0836124e6565b116134fd57601d19613500565b60465b6001850154608060020a9004600790810b900b019050600081121561352657600061353d565b633b9aca008113613537578061353d565b633b9aca005b6001909401805460c060020a63ffffffff021960079690960b67ffffffffffffffff16608060020a0277ffffffffffffffff0000000000000000000000000000000019909116179490941690935550505050565b6135996138eb565b60008060056040518059106135ab5750595b90808252806020026020018201604052509250600090505b600581101561362e578381815181106135d857fe5b9060200190602002015163ffffffff169150613610826006848154811015156135fd57fe5b906000526020600020906002020161330f565b83828151811061361c57fe5b602090810290910101526001016135c3565b5050919050565b6000816402540be4000a826001016402540be4000a8481151561365457fe5b0681151561365e57fe5b049392505050565b6000751aba4714957d300d0e549208b31adb1000000000000076010b46c6cdd6e3e0828f4db456ff0c8ea000000000000083613367565b6000806136aa87846136f1565b701d6329f1c35ca4bfabb9f561000000000087026c0c9f2c9cd04674edea40000000870268056bc75e2d631000008702909201919091010191508190505095945050505050565b60008060016136ff85613781565b0201600a61370c856137b4565b020161271061371a856137e9565b0201620186a08302016305f5e100613731856137f8565b02016402540be40061374285613827565b020164e8d4a5100061375385613858565b0201655af3107a40006137658561388a565b0201662386f26fc10000613778856138c2565b02019392505050565b600073af298d050e4395d69670b12b7f410000000000007406d79f82328ea3da61e066ebb2f88a00000000000083613367565b60007406d79f82328ea3da61e066ebb2f88a000000000000751aba4714957d300d0e549208b31adb1000000000000083613367565b6000612710620186a083613367565b6000710b7abc627050305adf14a3d9e4000000000072047bf19673df52e37f2410011d10000000000083613367565b600072047bf19673df52e37f2410011d1000000000007301c06a5ec5433c60ddaa16406f5a40000000000083613367565b60007301c06a5ec5433c60ddaa16406f5a40000000000073af298d050e4395d69670b12b7f4100000000000083613367565b600076010b46c6cdd6e3e0828f4db456ff0c8ea0000000000000766867a5a867f103b2fffa5a71fba0e7b68000000000000083613367565b60006ec097ce7bc90715b34b9f10000000006f4b3b4ca85a86c47a098a22400000000083613367565b60206040519081016040526000815290565b60c06040519081016040908152600080835260208301819052908201819052606082018190526080820181905260a082015290565b8154818355818115116111fa576000838152602090206111fa916110629160029182028101918502015b80821115613976576000808255600182015560020161395c565b50905600a165627a7a72305820c68b552b70bc95684b1c4fa9f9cf52e9806fbbf5e2141b9124f61d0fd229c0150029
Swarm Source
bzzr://c68b552b70bc95684b1c4fa9f9cf52e9806fbbf5e2141b9124f61d0fd229c015
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.
Add Token to MetaMask (Web3)