Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 12,276 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Approve | 6790131 | 2050 days ago | IN | 0 ETH | 0.00016295 | ||||
Start PVE | 6749121 | 2057 days ago | IN | 0.01 ETH | 0.00011313 | ||||
Start PVE | 6749118 | 2057 days ago | IN | 0.01 ETH | 0.00011313 | ||||
Approve | 6093737 | 2165 days ago | IN | 0 ETH | 0.00004723 | ||||
Approve | 6093734 | 2165 days ago | IN | 0 ETH | 0.00004723 | ||||
Approve | 6093724 | 2165 days ago | IN | 0 ETH | 0.00004723 | ||||
Approve | 6093631 | 2165 days ago | IN | 0 ETH | 0.00004723 | ||||
Approve | 6093628 | 2165 days ago | IN | 0 ETH | 0.00004723 | ||||
Approve | 6093621 | 2165 days ago | IN | 0 ETH | 0.00004723 | ||||
Approve | 6093616 | 2165 days ago | IN | 0 ETH | 0.00004723 | ||||
Approve | 6093595 | 2165 days ago | IN | 0 ETH | 0.00004723 | ||||
Create Miner Auc... | 5448621 | 2277 days ago | IN | 0 ETH | 0.00019179 | ||||
Create Miner Auc... | 5448449 | 2277 days ago | IN | 0 ETH | 0.0001918 | ||||
Create Miner Auc... | 5448388 | 2277 days ago | IN | 0 ETH | 0.00019182 | ||||
Create Miner Auc... | 5448351 | 2277 days ago | IN | 0 ETH | 0.00019181 | ||||
Sign Up For Tour... | 5445727 | 2277 days ago | IN | 0.000405 ETH | 0.00020295 | ||||
Create Sale Auct... | 5444031 | 2278 days ago | IN | 0 ETH | 0.00027124 | ||||
Create Sale Auct... | 5443774 | 2278 days ago | IN | 0 ETH | 0.00027124 | ||||
Create Sale Auct... | 5443771 | 2278 days ago | IN | 0 ETH | 0.00040687 | ||||
Create Sale Auct... | 5443768 | 2278 days ago | IN | 0 ETH | 0.00027124 | ||||
Create Sale Auct... | 5443690 | 2278 days ago | IN | 0 ETH | 0.00040687 | ||||
Finish PVE Batch | 5443689 | 2278 days ago | IN | 0 ETH | 0.00035446 | ||||
Create Sale Auct... | 5443028 | 2278 days ago | IN | 0 ETH | 0.00012062 | ||||
Sign Up For Tour... | 5441878 | 2278 days ago | IN | 0.00430339 ETH | 0.00018798 | ||||
Sign Up For Tour... | 5441873 | 2278 days ago | IN | 0.00426205 ETH | 0.00018772 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
5445727 | 2277 days ago | 0.00001215 ETH | ||||
5445727 | 2277 days ago | 0.00039285 ETH | ||||
5443689 | 2278 days ago | 0.002 ETH | ||||
5441878 | 2278 days ago | 0.00008861 ETH | ||||
5441878 | 2278 days ago | 0.00421478 ETH | ||||
5441873 | 2278 days ago | 0.00008775 ETH | ||||
5441873 | 2278 days ago | 0.00417429 ETH | ||||
5441871 | 2278 days ago | 0.00008691 ETH | ||||
5441871 | 2278 days ago | 0.00413419 ETH | ||||
5441868 | 2278 days ago | 0.00008608 ETH | ||||
5441868 | 2278 days ago | 0.00409447 ETH | ||||
5441866 | 2278 days ago | 0.00012541 ETH | ||||
5441866 | 2278 days ago | 0.00405513 ETH | ||||
5441864 | 2278 days ago | 0.00008443 ETH | ||||
5441864 | 2278 days ago | 0.00401618 ETH | ||||
5441864 | 2278 days ago | 0.00008362 ETH | ||||
5441864 | 2278 days ago | 0.00397759 ETH | ||||
5441862 | 2278 days ago | 0.00012183 ETH | ||||
5441862 | 2278 days ago | 0.00393938 ETH | ||||
5441437 | 2278 days ago | 0.008 ETH | ||||
5440854 | 2278 days ago | 0.00012066 ETH | ||||
5440854 | 2278 days ago | 0.00390154 ETH | ||||
5440790 | 2278 days ago | 0.0001195 ETH | ||||
5440790 | 2278 days ago | 0.00386406 ETH | ||||
5440766 | 2278 days ago | 0.002 ETH |
Loading...
Loading
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
[{"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
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.