├── .gitignore ├── BattleHeroBreeder.sol ├── BattleHeroBurnWallet.sol ├── BattleHeroChestShop.sol ├── BattleHeroMarketplace.sol ├── BattleHeroPE.sol ├── BattleHeroStaker.sol ├── BattleHeroStarterPack.sol ├── BattleHeroTrainer.sol ├── BattleHeroUpgrader.sol ├── README.md ├── deployed ├── BattleHero.sol ├── BattleHeroFactory.sol └── BattleHeroRewardWallet.sol └── shared ├── BattleHeroData.sol ├── DateTime.sol ├── IBattleHero.sol ├── IBattleHeroAirdrop.sol ├── IBattleHeroBreeder.sol ├── IBattleHeroFactory.sol ├── IBattleHeroGenScience.sol ├── IBattleHeroPE.sol ├── IBattleHeroRewardWallet.sol └── Whitelist.sol /.gitignore: -------------------------------------------------------------------------------- 1 | BattleHeroGenScience.sol 2 | BattleHeroCrafter.sol 3 | BattleHeroPrivateSaleWallet.sol 4 | BattleHeroCoinMigration.sol 5 | BattleHeroFaucet.sol 6 | testnet -------------------------------------------------------------------------------- /BattleHeroBreeder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.9; 3 | import "../node_modules/@openzeppelin/contracts/utils/Strings.sol"; 4 | import "../node_modules/@openzeppelin/contracts/access/AccessControlEnumerable.sol"; 5 | import "./shared/IBattleHeroFactory.sol"; 6 | import "./shared/IBattleHero.sol"; 7 | import "./shared/IBattleHeroGenScience.sol"; 8 | 9 | 10 | contract BattleHeroBreeder is 11 | AccessControlEnumerable { 12 | 13 | bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); 14 | bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); 15 | bytes32 public constant BREED_ROLE = keccak256("BREED_ROLE"); 16 | 17 | IBattleHeroGenScience _genScience; 18 | IBattleHeroFactory _erc721factory; 19 | 20 | using Strings for uint256; 21 | 22 | constructor( 23 | address genScience, 24 | address erc721) { 25 | _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); 26 | _setupRole(BREED_ROLE, _msgSender()); 27 | setGenScience(genScience); 28 | setERC721Factory(erc721); 29 | } 30 | modifier isSetup() { 31 | require(address(_genScience) != address(0), "Setup not correctly"); 32 | require(address(_erc721factory) != address(0), "Setup not correctly"); 33 | _; 34 | } 35 | function setGenScience(address genScience) public{ 36 | require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender())); 37 | _genScience = IBattleHeroGenScience(genScience); 38 | } 39 | function setERC721Factory(address erc721) public{ 40 | require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender())); 41 | _erc721factory = IBattleHeroFactory(erc721); 42 | } 43 | function addBreeder(address breeder) public { 44 | require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Invalid role for add breder"); 45 | _setupRole(BREED_ROLE, breeder); 46 | } 47 | function breed(address to, string memory gen) isSetup public returns(uint) { 48 | require(hasRole(BREED_ROLE, _msgSender()), "Invalid role for breed"); 49 | uint tokenId = _erc721factory.mint(to, gen); 50 | return tokenId; 51 | } 52 | function breedRandom() isSetup public returns (uint){ 53 | require(hasRole(BREED_ROLE, _msgSender()), "Invalid role for breed random"); 54 | string memory randomGen = _genScience.generate(); 55 | return breed(msg.sender, randomGen); 56 | } 57 | } -------------------------------------------------------------------------------- /BattleHeroBurnWallet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.9; 3 | import "../node_modules/@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol"; 4 | import "../node_modules/@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; 5 | import "./shared/IBattleHeroFactory.sol"; 6 | import "./shared/IBattleHero.sol"; 7 | import "./shared/IBattleHeroGenScience.sol"; 8 | import "./shared/IBattleHero.sol"; 9 | import "../node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 10 | 11 | 12 | contract BattleHeroBurnWallet is 13 | AccessControlEnumerableUpgradeable { 14 | 15 | bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); 16 | 17 | function initialize() public initializer{ 18 | __AccessControlEnumerable_init(); 19 | _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); 20 | _setupRole(BURNER_ROLE, _msgSender()); 21 | } 22 | function setBurnerRole(address burner) public { 23 | require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender())); 24 | _setupRole(BURNER_ROLE, burner); 25 | } 26 | function burn(address token, uint256 amount) public virtual{ 27 | require(IBattleHero(token).balanceOf(address(this)) >= amount); 28 | require(hasRole(BURNER_ROLE, _msgSender())); 29 | IBattleHero(token).burn(amount); 30 | } 31 | } -------------------------------------------------------------------------------- /BattleHeroChestShop.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.9; 3 | import "./shared/IBattleHero.sol"; 4 | import "./shared/IBattleHeroGenScience.sol"; 5 | import "./shared/IBattleHeroBreeder.sol"; 6 | import "../node_modules/@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; 7 | import "../node_modules/@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol"; 8 | 9 | contract BattleHeroChestShop is ContextUpgradeable, AccessControlEnumerableUpgradeable { 10 | 11 | uint256 public CHARACTER_CHEST; 12 | uint256 public WEAPON_CHEST; 13 | uint256 public MIX_CHEST; 14 | 15 | using SafeMathUpgradeable for uint256; 16 | 17 | mapping(address => mapping(uint256 => uint256)) _balances; 18 | mapping(uint256 => uint256) _prices; 19 | 20 | IBattleHero _battleHero; 21 | IBattleHeroBreeder _battleHeroBreeder; 22 | IBattleHeroGenScience _battleHeroGenScience; 23 | 24 | address _battleHeroBurnWallet; 25 | 26 | event ChestPurchased(address who, uint256 chestId, uint256 when); 27 | event ChestOpened(address who, uint256 chestId, uint256[] tokenIds, uint256 when); 28 | 29 | function initialize( 30 | address _battleHeroContractAddress, 31 | address _battleHeroBreederContractAddress, 32 | address _battleHeroGenScienceContractAddress, 33 | address _battleHeroBurnWalletAddress 34 | ) public initializer { 35 | 36 | __Context_init(); 37 | __AccessControlEnumerable_init(); 38 | 39 | _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); 40 | 41 | CHARACTER_CHEST = 0; 42 | WEAPON_CHEST = 1; 43 | MIX_CHEST = 2; 44 | 45 | setBattleHero(_battleHeroContractAddress); 46 | setBattleHeroBreeder(_battleHeroBreederContractAddress); 47 | setBattleHeroGenScience(_battleHeroGenScienceContractAddress); 48 | 49 | _battleHeroBurnWallet = _battleHeroBurnWalletAddress; 50 | _prices[CHARACTER_CHEST] = 900 ether; 51 | _prices[WEAPON_CHEST] = 900 ether; 52 | _prices[MIX_CHEST] = 1440 ether; 53 | } 54 | 55 | function setBattleHero(address _battleHeroContractAddress) public { 56 | _battleHero = IBattleHero(_battleHeroContractAddress); 57 | } 58 | 59 | function setBattleHeroBreeder(address _battleHeroBreederContractAddress) public { 60 | _battleHeroBreeder = IBattleHeroBreeder(_battleHeroBreederContractAddress); 61 | } 62 | 63 | function setBattleHeroGenScience(address _battleHeroGenScienceContractAddress) public { 64 | _battleHeroGenScience = IBattleHeroGenScience(_battleHeroGenScienceContractAddress); 65 | } 66 | 67 | function balanceOf(address owner, uint256 chestId) public view returns(uint256){ 68 | return _balances[owner][chestId]; 69 | } 70 | function purchase(uint256 _chestId) public virtual{ 71 | uint256 _amount = 1; 72 | uint256 _calculatedPrice = _prices[_chestId] * _amount; 73 | require(_battleHero.balanceOf(msg.sender) >= _calculatedPrice, "Insufficient balance"); 74 | require(_battleHero.allowance(msg.sender, address(this)) >= _calculatedPrice, "Insufficient allowance"); 75 | _balances[msg.sender][_chestId] = _balances[msg.sender][_chestId].add(_amount); 76 | _battleHero.transferFrom(msg.sender, _battleHeroBurnWallet, _calculatedPrice); 77 | emit ChestPurchased(msg.sender, _chestId, block.timestamp); 78 | } 79 | function purchase(uint256 _chestId, uint256 _amount) public virtual{ 80 | uint256 _calculatedPrice = _prices[_chestId] * _amount; 81 | require(_battleHero.balanceOf(msg.sender) >= _calculatedPrice, "Insufficient balance"); 82 | require(_battleHero.allowance(msg.sender, address(this)) >= _calculatedPrice, "Insufficient allowance"); 83 | _balances[msg.sender][_chestId] = _balances[msg.sender][_chestId].add(_amount); 84 | _battleHero.transferFrom(msg.sender, _battleHeroBurnWallet, _calculatedPrice); 85 | emit ChestPurchased(msg.sender, _chestId, block.timestamp); 86 | } 87 | function open(uint256 _chestId) public virtual{ 88 | require(_balances[msg.sender][_chestId] >= 1, "You should to buy more chests"); 89 | _openChest(_chestId); 90 | } 91 | function open(uint256 _chestId, uint256 _amount) public virtual{ 92 | require(_balances[msg.sender][_chestId] >= _amount, "You should to buy more chests"); 93 | for(uint i = 0; i < _amount; i++){ 94 | _openChest(_chestId); 95 | } 96 | } 97 | 98 | function _openChest(uint256 _chestId) internal { 99 | uint256[] memory _tokenIds = new uint256[](2); 100 | if(_chestId == 0){ 101 | string memory _genCharacter = _battleHeroGenScience.generateCharacter(); 102 | uint256 _characterId = _battleHeroBreeder.breed(msg.sender, _genCharacter); 103 | _tokenIds[0] = _characterId; 104 | } 105 | if(_chestId == 1){ 106 | string memory _genWeapon = _battleHeroGenScience.generateWeapon(); 107 | uint256 _weaponId = _battleHeroBreeder.breed(msg.sender, _genWeapon); 108 | _tokenIds[1] = _weaponId; 109 | } 110 | if(_chestId == 2){ 111 | string memory _genCharacter = _battleHeroGenScience.generateCharacter(); 112 | string memory _genWeapon = _battleHeroGenScience.generateWeapon(); 113 | uint256 _characterId = _battleHeroBreeder.breed(msg.sender, _genCharacter); 114 | uint256 _weaponId = _battleHeroBreeder.breed(msg.sender, _genWeapon); 115 | _tokenIds[0] = _characterId; 116 | _tokenIds[1] = _weaponId; 117 | } 118 | _balances[msg.sender][_chestId] = _balances[msg.sender][_chestId].sub(1); 119 | emit ChestOpened(msg.sender, _chestId, _tokenIds, block.timestamp); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /BattleHeroMarketplace.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.9; 3 | 4 | import "../node_modules/@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; 5 | import "../node_modules/@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; 6 | import "../node_modules/@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; 7 | import "../node_modules/@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; 8 | import "../node_modules/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; 9 | import "../node_modules/@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol"; 10 | import "../node_modules/@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol"; 11 | import "../node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 12 | 13 | import "./shared/BattleHeroData.sol"; 14 | import "./shared/IBattleHeroFactory.sol"; 15 | import "./shared/IBattleHero.sol"; 16 | 17 | 18 | contract BattleHeroMarketplace is 19 | ContextUpgradeable, 20 | AccessControlEnumerableUpgradeable{ 21 | 22 | using CountersUpgradeable for CountersUpgradeable.Counter; 23 | using SafeMathUpgradeable for uint256; 24 | 25 | struct Auction{ 26 | uint256 heroId; 27 | uint256 price; 28 | uint256 auctionId; 29 | address auctioner; 30 | } 31 | 32 | IBattleHeroFactory _battleHeroFactory; 33 | IBattleHero _battleHero; 34 | 35 | mapping(uint256 => Auction) _auctions; 36 | mapping(uint256 => bool) _heroesInAuction; 37 | mapping(uint256 => uint256) _heroesAuctionId; 38 | 39 | CountersUpgradeable.Counter private _auctionTracker; 40 | 41 | address _owner; 42 | address _battleHeroBurnWallet; 43 | uint256 FEE; 44 | 45 | event AuctionCreated(address seller, uint256 heroId, uint256 price); 46 | event AuctionFinished(address buyer, address seller, uint256 heroId, uint256 price); 47 | 48 | address _battleHeroReserve; 49 | 50 | function initialize( 51 | address _battleHeroFactoryAddress, 52 | address _battleHeroAddress, 53 | address _battleHeroBurnWalletAddress, 54 | address _battleHeroReserveWallet 55 | ) public initializer { 56 | __Context_init(); 57 | __AccessControlEnumerable_init(); 58 | _owner = msg.sender; 59 | _battleHeroBurnWallet = _battleHeroBurnWalletAddress; 60 | FEE = 5; 61 | setBattleHeroFactory(_battleHeroFactoryAddress); 62 | setBattleHero(_battleHeroAddress); 63 | setBattleHeroReserve(_battleHeroReserveWallet); 64 | } 65 | function setBattleHeroReserve(address reserve) public { 66 | require(msg.sender == _owner); 67 | require(reserve != address(0)); 68 | _battleHeroReserve = reserve; 69 | } 70 | function setBattleHeroFactory(address battleHeroFactoryAddress) public { 71 | require(msg.sender == _owner); 72 | require(battleHeroFactoryAddress != address(0)); 73 | _battleHeroFactory = IBattleHeroFactory(battleHeroFactoryAddress); 74 | } 75 | function setBattleHero(address battleHeroAddress) public { 76 | require(msg.sender == _owner); 77 | require(battleHeroAddress != address(0)); 78 | _battleHero = IBattleHero(battleHeroAddress); 79 | } 80 | 81 | function setBattleHeroBurnWallet(address battleHeroBurnWalletAddress) public { 82 | require(msg.sender == _owner); 83 | require(battleHeroBurnWalletAddress != address(0)); 84 | _battleHeroBurnWallet = battleHeroBurnWalletAddress; 85 | } 86 | 87 | function createAuction( 88 | uint256 _heroId, 89 | uint256 _price 90 | ) public { 91 | require(!_heroesInAuction[_heroId], "Hero currently in auction"); 92 | require(!_battleHeroFactory.isLocked(_heroId), "Herro currently locked"); 93 | require(_battleHeroFactory.isApproved(address(this), _heroId), "Unnapproved hero"); 94 | require(_battleHeroFactory.ownerOf(_heroId) == msg.sender, "You are not owner"); 95 | require(_price > 0, "Invalid price"); 96 | uint256 _currentAuction = _auctionTracker.current(); 97 | _auctions[_currentAuction] = Auction(_heroId, _price, _currentAuction , msg.sender); 98 | _heroesAuctionId[_heroId] = _currentAuction; 99 | _heroesInAuction[_heroId] = true; 100 | _auctionTracker.increment(); 101 | _battleHeroFactory.lockHero(_heroId); 102 | emit AuctionCreated(msg.sender, _heroId, _price); 103 | } 104 | 105 | function purchase(uint256 _auctionId) public { 106 | Auction memory _auction = getAuction(_auctionId); 107 | address heroOwner = _battleHeroFactory.ownerOf(_auction.heroId); 108 | require(_battleHero.allowance(msg.sender, address(this)) >= _auction.price, "Insufficient allowance"); 109 | require(_battleHero.balanceOf(msg.sender) >= _auction.price, "Insufficient balance"); 110 | require(_battleHeroFactory.isApproved(address(this), _auction.heroId), "Unnapproved hero"); 111 | require(_battleHeroFactory.isLocked(_auction.heroId), "Herro currently not locked"); 112 | require(_heroesInAuction[_auction.heroId], "Hero currently not in auction"); 113 | require(heroOwner != msg.sender, "Owner can not buy his NFT"); 114 | _processPurchase(_auction); 115 | _removeAuction(_auctionId); 116 | emit AuctionFinished(msg.sender, heroOwner, _auction.heroId, _auction.price); 117 | } 118 | 119 | function isSelling(uint256 tokenId) public view returns(bool){ 120 | return _heroesInAuction[tokenId]; 121 | } 122 | 123 | function getAuction(uint256 _auctionId) public view returns(Auction memory){ 124 | return _auctions[_auctionId]; 125 | } 126 | 127 | function totalAuctions() public view returns(uint256){ 128 | return _auctionTracker.current(); 129 | } 130 | 131 | function auctionIdOfHero(uint256 _heroId) public view returns(uint256){ 132 | return _heroesAuctionId[_heroId]; 133 | } 134 | 135 | function cancelAuction(uint256 _auctionId) public { 136 | Auction memory _auction = getAuction(_auctionId); 137 | require(_battleHeroFactory.ownerOf(_auction.heroId) == msg.sender, "You are not owner"); 138 | require(_battleHeroFactory.isLocked(_auction.heroId), "Herro currently not locked"); 139 | require(_heroesInAuction[_auction.heroId], "Hero currently not in auction"); 140 | _removeAuction(_auctionId); 141 | } 142 | 143 | function _processPurchase(Auction memory _auction) private { 144 | uint256 _calculatedFee = _auction.price.mul(FEE).div(100); 145 | uint256 _reserveFee = _calculatedFee.mul(20).div(100); 146 | uint256 _burnFee = _calculatedFee.mul(80).div(100); 147 | _battleHeroFactory.unlockHero(_auction.heroId); 148 | require(!_battleHeroFactory.isLocked(_auction.heroId)); 149 | _battleHeroFactory.transferFrom(_auction.auctioner, msg.sender, _auction.heroId); 150 | _battleHero.transferFrom(msg.sender, _battleHeroBurnWallet, _burnFee); 151 | _battleHero.transferFrom(msg.sender, _battleHeroReserve, _reserveFee); 152 | _battleHero.transferFrom(msg.sender, _auction.auctioner, (_auction.price) - _calculatedFee); 153 | } 154 | 155 | function _removeAuction(uint256 _auctionId) private { 156 | // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and 157 | // then delete the last slot (swap and pop). 158 | Auction memory _auction = _auctions[_auctionId]; 159 | uint256 lastAuctionId = totalAuctions() - 1; 160 | _battleHeroFactory.unlockHero(_auction.heroId); 161 | // Si el ultimoID es igual al que queremos eliminar no hace falta el swap 162 | if(_auctionId != lastAuctionId){ 163 | Auction memory _gapAuction = _auctions[lastAuctionId]; 164 | _gapAuction.auctionId = _auctionId; 165 | _auctions[_auction.auctionId] = _gapAuction; 166 | _heroesAuctionId[_gapAuction.heroId] = _auction.auctionId; 167 | _auctions[lastAuctionId] = _auction; 168 | } 169 | 170 | delete _heroesAuctionId[_auction.heroId]; 171 | delete _heroesInAuction[_auction.heroId]; 172 | delete _auctions[lastAuctionId]; 173 | _auctionTracker.decrement(); 174 | } 175 | } -------------------------------------------------------------------------------- /BattleHeroPE.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.9; 3 | import "../node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 4 | import "../node_modules/@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; 5 | import "../node_modules/@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; 6 | import "../node_modules/@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol"; 7 | import "./shared/IBattleHeroRewardWallet.sol"; 8 | 9 | 10 | contract BattleHeroPE is ContextUpgradeable, AccessControlEnumerableUpgradeable{ 11 | 12 | bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); 13 | mapping(address => mapping(address => uint256)) private _allowances; 14 | 15 | using SafeMathUpgradeable for uint256; 16 | 17 | mapping(address => uint256) _balances; 18 | 19 | uint8 _decimals; 20 | uint256 _scale; 21 | uint256 _ratio; 22 | 23 | IBattleHeroRewardWallet _rewardWallet; 24 | 25 | event PEExchanged(address who, uint256 amount); 26 | 27 | function initialize( 28 | address _rewardWalletAddress 29 | ) public initializer { 30 | __Context_init(); 31 | __AccessControlEnumerable_init(); 32 | _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); 33 | _rewardWallet = IBattleHeroRewardWallet(_rewardWalletAddress); 34 | _decimals = 18; 35 | _scale = 1 * 10 ** _decimals; 36 | _ratio = 5; 37 | } 38 | 39 | function exchange(uint256 amount, address _token) public{ 40 | uint256 _balance = _balances[msg.sender]; 41 | require(_balance > 0, "You dont have balance to exchange"); 42 | require(_balance >= amount, "Amount excedeed balance"); 43 | uint256 _reward = _PEtoBath(_balance); 44 | _rewardWallet.distribute(_token, _reward, msg.sender); 45 | _balances[msg.sender] = _balances[msg.sender].sub(amount); 46 | emit PEExchanged(msg.sender, amount); 47 | } 48 | 49 | function balanceOf(address account) public view virtual returns (uint256) { 50 | return _balances[account]; 51 | } 52 | 53 | function approve(address spender, uint256 amount) public { 54 | _allowances[msg.sender][spender] += amount; 55 | } 56 | 57 | function setMinterRole(address minter) public { 58 | require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Only admin can set a minter"); 59 | _setupRole(MINTER_ROLE, minter); 60 | } 61 | 62 | function mint(address to, uint256 amount) public{ 63 | require(hasRole(MINTER_ROLE, _msgSender()), "You dont have a minter role"); 64 | _balances[to] += amount; 65 | } 66 | function burnFrom(address from, uint256 amount) public{ 67 | require(_allowances[from][msg.sender] >= amount); 68 | burn(from, amount); 69 | } 70 | function burn(address to, uint256 amount) public { 71 | require(hasRole(MINTER_ROLE, _msgSender()), "You dont have a minter role"); 72 | _balances[to] -= amount; 73 | } 74 | 75 | function _PEtoBath(uint256 _pe) internal view returns(uint256){ 76 | return _pe.div(_ratio); 77 | } 78 | 79 | function scale(uint256 _peEther) public view returns(uint256){ 80 | return _peEther * _scale; 81 | } 82 | 83 | function changeRatio(uint256 _newRatio) public { 84 | require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Only admin can change ratio"); 85 | require(_newRatio > 0); 86 | _ratio = _newRatio; 87 | } 88 | 89 | function changeRewardWallet(address _newRewardWallet) public { 90 | require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Only admin can change reward wallet"); 91 | require(_newRewardWallet != address(0)); 92 | _rewardWallet = IBattleHeroRewardWallet(_newRewardWallet); 93 | } 94 | 95 | } -------------------------------------------------------------------------------- /BattleHeroStaker.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.9; 3 | 4 | import "../node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 5 | import "../node_modules/@openzeppelin/contracts/utils/math/SafeMath.sol"; 6 | import "../node_modules/@openzeppelin/contracts/utils/Context.sol"; 7 | import "./shared/IBattleHero.sol"; 8 | 9 | 10 | contract BattleHeroStaker is Context{ 11 | 12 | 13 | 14 | 15 | } -------------------------------------------------------------------------------- /BattleHeroStarterPack.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.9; 3 | 4 | import "../node_modules/@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; 5 | import "../node_modules/@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol"; 6 | import "../node_modules/@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; 7 | import "./shared/IBattleHero.sol"; 8 | import "./shared/IBattleHeroGenScience.sol"; 9 | import "./shared/IBattleHeroBreeder.sol"; 10 | 11 | contract BattleHeroStarterPack is ContextUpgradeable, AccessControlEnumerableUpgradeable{ 12 | 13 | mapping(address => bool) _starterPackClaimed; 14 | 15 | bool _paused; 16 | 17 | address _owner; 18 | 19 | IBattleHeroBreeder _battleHeroBreeder; 20 | IBattleHeroGenScience _battleHeroGenScience; 21 | 22 | event StarterPackClaimed(address who, uint256[] tokenIds); 23 | 24 | function initialize( 25 | address _battleHeroBreederAddress, 26 | address _battleHeroGenScienceAddress 27 | ) public initializer { 28 | __Context_init(); 29 | __AccessControlEnumerable_init(); 30 | _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); 31 | _paused = false; 32 | _battleHeroBreeder = IBattleHeroBreeder(_battleHeroBreederAddress); 33 | _battleHeroGenScience = IBattleHeroGenScience(_battleHeroGenScienceAddress); 34 | } 35 | 36 | function setBreeder(address _battleHeroBreederAddress) public { 37 | require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Invalid role for set breeder"); 38 | _battleHeroBreeder = IBattleHeroBreeder(_battleHeroBreederAddress); 39 | } 40 | function setGenScience(address _battleHeroGenScienceAddress) public { 41 | require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Invalid role for set gen science"); 42 | _battleHeroGenScience = IBattleHeroGenScience(_battleHeroGenScienceAddress); 43 | } 44 | 45 | function claim() public{ 46 | require(!_starterPackClaimed[msg.sender], "Starter pack claimed"); 47 | require(!_paused, "Starter pack is paused"); 48 | uint256[] memory _tokenIds = new uint256[](2); 49 | string memory _characterGen = _battleHeroGenScience.generateIntransferibleCharacter(IBattleHeroGenScience.Rarity.COMMON); 50 | string memory _weaponGen = _battleHeroGenScience.generateIntransferibleWeapon(IBattleHeroGenScience.Rarity.COMMON); 51 | uint256 _characterId = _battleHeroBreeder.breed(msg.sender, _characterGen); 52 | uint256 _weaponId = _battleHeroBreeder.breed(msg.sender, _weaponGen); 53 | _tokenIds[0] = _characterId; 54 | _tokenIds[1] = _weaponId; 55 | _starterPackClaimed[msg.sender] = true; 56 | emit StarterPackClaimed(msg.sender, _tokenIds); 57 | } 58 | function claimed(address from) public view returns(bool){ 59 | return _starterPackClaimed[from]; 60 | } 61 | function pause() public{ 62 | require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender())); 63 | _paused = true; 64 | } 65 | function upause() public{ 66 | require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender())); 67 | _paused = false; 68 | } 69 | } -------------------------------------------------------------------------------- /BattleHeroTrainer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.9; 3 | 4 | import "./shared/BattleHeroData.sol"; 5 | import "./shared/IBattleHeroFactory.sol"; 6 | import "./shared/IBattleHeroPE.sol"; 7 | import "./shared/IBattleHero.sol"; 8 | import "../node_modules/@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol"; 9 | import "../node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 10 | 11 | contract BattleHeroTrainer is Initializable { 12 | 13 | struct Slot{ 14 | uint256 hero; 15 | bool exists; 16 | uint256 when; 17 | } 18 | 19 | mapping(address => uint256) _slots; 20 | mapping(address => mapping(uint256 => mapping(uint256 => Slot))) _trainingPair; 21 | mapping(address => bool) _training; 22 | 23 | BattleHeroData _battleHeroData; 24 | IBattleHeroFactory _battleHeroFactory; 25 | IBattleHeroPE _battleHeroPE; 26 | IBattleHero _battleHero; 27 | 28 | address _owner; 29 | 30 | uint256 MIN_SLOTS; 31 | uint256 MAX_SLOTS; 32 | uint256 SLOT_PRICE; 33 | uint256 TRAINING_DURATION; 34 | 35 | 36 | using SafeMathUpgradeable for uint256; 37 | 38 | function initialize( 39 | address _battleHeroDataAddress, 40 | address _battleHeroFactoryAddress, 41 | address _battleHeroPEAddress, 42 | address _battleHeroAddress 43 | ) public initializer { 44 | MIN_SLOTS = 6; 45 | MAX_SLOTS = 30; 46 | SLOT_PRICE = 1500 ether; 47 | TRAINING_DURATION = 1 days; 48 | _owner = msg.sender; 49 | setBattleHeroData(_battleHeroDataAddress); 50 | setBattleHeroFactory(_battleHeroFactoryAddress); 51 | setBattleHeroPE(_battleHeroPEAddress); 52 | setBattleHero(_battleHeroAddress); 53 | } 54 | 55 | function setTrainDuration(uint256 _trainingTime) public{ 56 | require(msg.sender == _owner); 57 | TRAINING_DURATION = _trainingTime; 58 | } 59 | 60 | function setBattleHeroData(address battleHeroDataAddress) public { 61 | require(msg.sender == _owner); 62 | require(battleHeroDataAddress != address(0)); 63 | _battleHeroData = BattleHeroData(battleHeroDataAddress); 64 | } 65 | 66 | function setBattleHeroFactory(address battleHeroFactoryAddress) public { 67 | require(msg.sender == _owner); 68 | require(battleHeroFactoryAddress != address(0)); 69 | _battleHeroFactory = IBattleHeroFactory(battleHeroFactoryAddress); 70 | } 71 | 72 | function setBattleHeroPE(address battleHeroPEAddress) public { 73 | require(msg.sender == _owner); 74 | require(battleHeroPEAddress != address(0)); 75 | _battleHeroPE = IBattleHeroPE(battleHeroPEAddress); 76 | } 77 | 78 | function setBattleHero(address battleHeroAddress) public { 79 | require(msg.sender == _owner); 80 | require(battleHeroAddress != address(0)); 81 | _battleHero = IBattleHero(battleHeroAddress); 82 | } 83 | 84 | function isTraining(address from, uint256 heroId) public view returns(bool){ 85 | bool _tr = false; 86 | for(uint i = 0; i < _slots[from]; i++){ 87 | if(_trainingPair[from][i][0].hero == heroId || _trainingPair[from][i][1].hero == heroId){ 88 | if(_trainingPair[from][i][0].exists == true || _trainingPair[from][i][1].exists == true){ 89 | _tr = true; 90 | } 91 | } 92 | } 93 | return _tr; 94 | } 95 | 96 | function slots(address from) public view returns(uint256){ 97 | if(_slots[from] == 0){ 98 | return MIN_SLOTS; 99 | } 100 | return _slots[from] + MIN_SLOTS; 101 | } 102 | 103 | function getSlot(address from, uint256 slot) public view returns(Slot memory, Slot memory) { 104 | return (_trainingPair[from][slot][0], _trainingPair[from][slot][1]); 105 | } 106 | 107 | function train(uint256[] memory _characters , uint256[] memory _weapons) public virtual { 108 | require(_characters.length == _weapons.length, "Invalid pairs"); 109 | for(uint i = 0; i < _characters.length; i++){ 110 | uint256 _character = _characters[i]; 111 | uint256 _weapon = _weapons[i]; 112 | trainPair(i, _character, _weapon); 113 | } 114 | } 115 | 116 | function claimSlots(uint256[] memory _slotsToClaim) public virtual { 117 | uint256 _peTotal = 0; 118 | for(uint i = 0; i < _slotsToClaim.length; i++){ 119 | _preClaim(_slotsToClaim[i]); 120 | uint256 _peCalculated = calculateBySlot(_slotsToClaim[i]); 121 | _peTotal = _peTotal + _peCalculated; 122 | removeTrainPair(_slotsToClaim[i]); 123 | } 124 | _battleHeroPE.mint(msg.sender, _battleHeroPE.scale(_peTotal)); 125 | } 126 | 127 | function claimAll() public virtual { 128 | uint256 _peTotal = 0; 129 | uint256 _sl = slots(msg.sender); 130 | for(uint i = 0; i < _sl; i++){ 131 | _preClaim(i); 132 | uint256 _peCalculated = calculateBySlot(i); 133 | _peTotal = _peTotal + _peCalculated; 134 | removeTrainPair(i); 135 | } 136 | _training[msg.sender] = false; 137 | _battleHeroPE.mint(msg.sender, _battleHeroPE.scale(_peTotal)); 138 | } 139 | 140 | function claimPair(uint256 slot) public { 141 | _preClaim(slot); 142 | Slot memory _characterSlot = _trainingPair[msg.sender][slot][0]; 143 | Slot memory _weaponSlot = _trainingPair[msg.sender][slot][1]; 144 | IBattleHeroFactory.Hero memory _character = _battleHeroFactory.heroeOfId(_characterSlot.hero); 145 | IBattleHeroFactory.Hero memory _weapon = _battleHeroFactory.heroeOfId(_weaponSlot.hero); 146 | uint256 _peTotal = _calculateByHeroes(_character, _weapon); 147 | _battleHeroPE.mint(msg.sender, _peTotal); 148 | removeTrainPair(slot); 149 | } 150 | 151 | function _calculateByHeroes( 152 | IBattleHeroFactory.Hero memory _character, 153 | IBattleHeroFactory.Hero memory _weapon 154 | ) internal view returns(uint256){ 155 | uint256 _peTotal = 0; 156 | if(_character.exists){ 157 | uint256 _characterCalculated = _calculate(_character.deconstructed._rarity); 158 | _peTotal = _peTotal + _characterCalculated; 159 | } 160 | if(_weapon.exists){ 161 | uint256 _weaponCalculated = _calculate(_weapon.deconstructed._rarity); 162 | _peTotal = _peTotal + _weaponCalculated; 163 | } 164 | BattleHeroData.Rarity memory _characterRarity = _battleHeroData.getRarity(_character.deconstructed._rarity); 165 | BattleHeroData.Rarity memory _weaponRarity = _battleHeroData.getRarity(_weapon.deconstructed._rarity); 166 | 167 | if(_isRarityBonus(_characterRarity, _weaponRarity)){ 168 | uint256 bonus = _peTotal.mul(5).div(100); 169 | _peTotal = _peTotal + bonus; 170 | } 171 | 172 | if(_isRandomBonus(_character, _weapon)){ 173 | uint256 bonus = _peTotal.mul(5).div(100); 174 | _peTotal = _peTotal + bonus; 175 | } 176 | 177 | return _peTotal; 178 | } 179 | 180 | function calculateBySlot(uint256 slot) public view returns(uint256){ 181 | uint256 _peTotal = 0; 182 | Slot memory _characterSlot = _trainingPair[msg.sender][slot][0]; 183 | Slot memory _weaponSlot = _trainingPair[msg.sender][slot][1]; 184 | if(_characterSlot.exists){ 185 | IBattleHeroFactory.Hero memory _character = _battleHeroFactory.heroeOfId(_characterSlot.hero); 186 | uint256 _characterCalculated = _calculate(_character.deconstructed._rarity); 187 | _peTotal = _peTotal + _characterCalculated; 188 | } 189 | if(_weaponSlot.exists){ 190 | IBattleHeroFactory.Hero memory _weapon = _battleHeroFactory.heroeOfId(_weaponSlot.hero); 191 | uint256 _weaponCalculated = _calculate(_weapon.deconstructed._rarity); 192 | _peTotal = _peTotal + _weaponCalculated; 193 | } 194 | return _peTotal; 195 | } 196 | 197 | function calculate(uint256[] memory _ids) public view returns(uint256){ 198 | uint256 _pe = 0; 199 | for(uint256 i = 0; i < _ids.length; i++){ 200 | _pe = _pe.add(_calculate(_ids[i])); 201 | } 202 | return _pe; 203 | } 204 | 205 | function cancel() public { 206 | for(uint i = 0; i < slots(msg.sender); i++){ 207 | removeTrainPair(i); 208 | } 209 | } 210 | 211 | function purchaseExtraSlot() public{ 212 | require(_battleHero.balanceOf(msg.sender) >= SLOT_PRICE); 213 | require(_battleHero.allowance(msg.sender, address(this)) >= SLOT_PRICE); 214 | uint256 _currentSlots = slots(msg.sender); 215 | require(_currentSlots <= MAX_SLOTS, "You reach max slots"); 216 | _slots[msg.sender] = _slots[msg.sender] + 1; 217 | _battleHero.burnFrom(msg.sender, SLOT_PRICE); 218 | } 219 | 220 | function trainPair( 221 | uint256 slot, 222 | uint256 character, 223 | uint256 weapon 224 | ) public { 225 | require(_battleHeroFactory.ownerOf(character) == msg.sender, "You are not the hero owner"); 226 | require(_battleHeroFactory.ownerOf(weapon) == msg.sender, "You are not the hero owner"); 227 | require(_battleHeroFactory.heroeOfId(character).exists, "Hero doesnt exists"); 228 | require(_battleHeroFactory.heroeOfId(weapon).exists , "Hero doesnt exists"); 229 | require(!_trainingPair[msg.sender][slot][0].exists , "Slot for this character is full"); 230 | require(!_trainingPair[msg.sender][slot][1].exists , "Slot for this weapon is full"); 231 | require(!_battleHeroFactory.isLocked(character) , "This character is locked"); 232 | require(!_battleHeroFactory.isLocked(weapon) , "This weapon is locked"); 233 | require(!_isWeapon(character) , "Invalid pair"); 234 | require(_isWeapon(weapon) , "Invalid pair"); 235 | uint256 _now = block.timestamp; 236 | _trainingPair[msg.sender][slot][0] = Slot(character, true, _now); 237 | _trainingPair[msg.sender][slot][1] = Slot(weapon, true, _now); 238 | _battleHeroFactory.lockHero(character); 239 | _battleHeroFactory.lockHero(weapon); 240 | } 241 | function removeTrainPair( 242 | uint256 slot 243 | ) public { 244 | _battleHeroFactory.unlockHero(_trainingPair[msg.sender][slot][0].hero); 245 | _battleHeroFactory.unlockHero(_trainingPair[msg.sender][slot][1].hero); 246 | _trainingPair[msg.sender][slot][0] = Slot(0, false, 0); 247 | _trainingPair[msg.sender][slot][1] = Slot(0, false, 0); 248 | delete _trainingPair[msg.sender][slot][0]; 249 | delete _trainingPair[msg.sender][slot][1]; 250 | } 251 | function _preClaim(uint256 _sl) internal view { 252 | if(_trainingPair[msg.sender][_sl][0].exists){ 253 | require(block.timestamp >= (_trainingPair[msg.sender][_sl][0].when + TRAINING_DURATION), "Train not finished"); 254 | require(block.timestamp >= (_trainingPair[msg.sender][_sl][1].when + TRAINING_DURATION), "Train not finished"); 255 | } 256 | } 257 | function _calculate( 258 | uint256 gen 259 | ) internal view returns(uint256){ 260 | BattleHeroData.TrainingLevel memory trainingLevel = _battleHeroData.getTrainingLevel(gen); 261 | return _battleHeroPE.scale((trainingLevel.level * trainingLevel.pct)) / 100; 262 | } 263 | function _isWeapon( 264 | uint256 tokenId 265 | ) internal view returns (bool){ 266 | IBattleHeroFactory.Hero memory hero = _battleHeroFactory.heroeOfId(tokenId); 267 | BattleHeroData.DeconstructedGen memory deconstructed = _battleHeroData.deconstructGen(hero.genetic); 268 | return deconstructed._type > 49; 269 | } 270 | function _isRarityBonus( 271 | BattleHeroData.Rarity memory _characterRarity, 272 | BattleHeroData.Rarity memory _weaponRarity 273 | ) internal view returns(bool){ 274 | if(_characterRarity.rare == _weaponRarity.rare){ 275 | uint256 _nonce = _characterRarity.max + _weaponRarity.min; 276 | uint256 _block = block.number; 277 | uint pct = 2 - 1; 278 | uint256 _result = uint8(uint256(keccak256(abi.encodePacked(_nonce, _block, block.difficulty)))) % pct; 279 | _result = _result + 1; 280 | return _result == 1; 281 | } 282 | return false; 283 | } 284 | function _isRandomBonus( 285 | IBattleHeroFactory.Hero memory _character, 286 | IBattleHeroFactory.Hero memory _weapon) internal view returns(bool){ 287 | if(!_character.exists || !_weapon.exists){ 288 | return false; 289 | } 290 | uint256 _nonce = _character.deconstructed._rarity + _weapon.deconstructed._rarity; 291 | uint256 _block = block.number; 292 | uint pct = 2 - 1; 293 | uint256 _result = uint8(uint256(keccak256(abi.encodePacked(_nonce, _block, block.difficulty)))) % pct; 294 | _result = _result + 1; 295 | return _result == 1; 296 | } 297 | } -------------------------------------------------------------------------------- /BattleHeroUpgrader.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.9; 3 | 4 | import "./shared/BattleHeroData.sol"; 5 | import "./shared/IBattleHeroFactory.sol"; 6 | import "./shared/IBattleHeroGenScience.sol"; 7 | import "./shared/IBattleHeroBreeder.sol"; 8 | import "./shared/IBattleHeroPE.sol"; 9 | import "./shared/IBattleHero.sol"; 10 | import "../node_modules/@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol"; 11 | import "../node_modules/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 12 | 13 | contract BattleHeroUpgrader is Initializable { 14 | 15 | IBattleHeroGenScience _battleHeroGenScience; 16 | IBattleHeroBreeder _battleHeroBreeder; 17 | IBattleHeroFactory _battleHeroFactory; 18 | IBattleHero _battleHero; 19 | BattleHeroData _battleHeroData; 20 | address _battleHeroBurnWallet; 21 | mapping(IBattleHeroGenScience.Rarity => uint256) _upgradePrices; 22 | event HeroUpgraded(uint256 heroId, address who); 23 | function initialize( 24 | address _battleHeroGenScienceAddress, 25 | address _battleHeroBreederAddress, 26 | address _battleHeroFactoryAddress, 27 | address _battleHeroAddress, 28 | address _battleHeroDataAddress, 29 | address _battleHeroBurnWalletAddress 30 | ) public initializer { 31 | _battleHeroFactory = IBattleHeroFactory(_battleHeroFactoryAddress); 32 | _battleHeroData = BattleHeroData(_battleHeroDataAddress); 33 | _battleHeroGenScience = IBattleHeroGenScience(_battleHeroGenScienceAddress); 34 | _battleHeroBreeder = IBattleHeroBreeder(_battleHeroBreederAddress); 35 | _battleHero = IBattleHero(_battleHeroAddress); 36 | _battleHeroBurnWallet = _battleHeroBurnWalletAddress; 37 | 38 | _upgradePrices[IBattleHeroGenScience.Rarity.LOW_RARE] = 50 ether; 39 | _upgradePrices[IBattleHeroGenScience.Rarity.RARE] = 150 ether; 40 | _upgradePrices[IBattleHeroGenScience.Rarity.EPIC] = 500 ether; 41 | _upgradePrices[IBattleHeroGenScience.Rarity.LEGEND] = 1000 ether; 42 | _upgradePrices[IBattleHeroGenScience.Rarity.MITIC] = 2000 ether; 43 | } 44 | 45 | function upgrade( 46 | uint256 _tokenId1, 47 | uint256 _tokenId2, 48 | uint256 _tokenId3 49 | ) public { 50 | 51 | IBattleHeroFactory.Hero memory _hero1 = _battleHeroFactory.heroeOfId(_tokenId1); 52 | IBattleHeroFactory.Hero memory _hero2 = _battleHeroFactory.heroeOfId(_tokenId2); 53 | IBattleHeroFactory.Hero memory _hero3 = _battleHeroFactory.heroeOfId(_tokenId3); 54 | 55 | BattleHeroData.Rarity memory _rarity1 = _battleHeroData.getRarity(_hero1.deconstructed._rarity); 56 | BattleHeroData.Rarity memory _rarity2 = _battleHeroData.getRarity(_hero2.deconstructed._rarity); 57 | BattleHeroData.Rarity memory _rarity3 = _battleHeroData.getRarity(_hero3.deconstructed._rarity); 58 | 59 | _preUpgrade(_hero1, _hero2, _hero3, _rarity1, _rarity2, _rarity3); 60 | _processUpgrade(_hero1, _rarity1); 61 | 62 | _battleHeroFactory.transferFrom(msg.sender, address(0x000000000000000000000000000000000000dEaD), _tokenId1); 63 | _battleHeroFactory.transferFrom(msg.sender, address(0x000000000000000000000000000000000000dEaD), _tokenId2); 64 | _battleHeroFactory.transferFrom(msg.sender, address(0x000000000000000000000000000000000000dEaD), _tokenId3); 65 | } 66 | 67 | function _processUpgrade( 68 | IBattleHeroFactory.Hero memory _hero, 69 | BattleHeroData.Rarity memory _rarity 70 | ) internal { 71 | uint _rare = uint(_rarity.rare); 72 | uint _maxRare = uint(BattleHeroData.Rare.MITIC); 73 | IBattleHeroGenScience.Rarity _upgradedRarity = _uintToRarity(_rare + 1); 74 | uint256 _upgradePrice = _upgradePrices[_upgradedRarity]; 75 | string memory _gen; 76 | require(_rare < _maxRare, "You reach max rarity"); 77 | require(_battleHero.balanceOf(msg.sender) >= _upgradePrice, "Insufficient BATH"); 78 | require(_battleHero.allowance(msg.sender, address(this)) >= _upgradePrice, "Insufficient allowance"); 79 | if(_isWeapon(_hero.deconstructed)){ 80 | _gen = _battleHeroGenScience.generateWeapon(_upgradedRarity, _padLeft(_hero.deconstructed._asset)); 81 | }else{ 82 | _gen = _battleHeroGenScience.generateCharacter(_upgradedRarity, _padLeft(_hero.deconstructed._asset)); 83 | } 84 | uint256 _heroId = _battleHeroBreeder.breed(msg.sender, _gen); 85 | _battleHero.transferFrom(msg.sender, _battleHeroBurnWallet, _upgradePrice); 86 | emit HeroUpgraded(_heroId, msg.sender); 87 | } 88 | 89 | function price(uint256 heroId) public view returns(uint256){ 90 | IBattleHeroFactory.Hero memory _hero = _battleHeroFactory.heroeOfId(heroId); 91 | BattleHeroData.Rarity memory _rarity = _battleHeroData.getRarity(_hero.deconstructed._rarity); 92 | uint _rare = uint(_rarity.rare); 93 | IBattleHeroGenScience.Rarity _upgradedRarity = _uintToRarity(_rare + 1); 94 | return _upgradePrices[_upgradedRarity]; 95 | } 96 | 97 | function _preUpgrade( 98 | IBattleHeroFactory.Hero memory _hero1, 99 | IBattleHeroFactory.Hero memory _hero2, 100 | IBattleHeroFactory.Hero memory _hero3, 101 | BattleHeroData.Rarity memory _rarity1, 102 | BattleHeroData.Rarity memory _rarity2, 103 | BattleHeroData.Rarity memory _rarity3 104 | ) internal pure{ 105 | require(_hero1.deconstructed._asset == _hero2.deconstructed._asset, "Inconsistent hero"); 106 | require(_hero2.deconstructed._asset == _hero3.deconstructed._asset, "Inconsistent hero"); 107 | require(_hero3.deconstructed._asset == _hero1.deconstructed._asset, "Inconsistent hero"); 108 | 109 | require(_rarity1.rare == _rarity2.rare, "Inconsisten rarity"); 110 | require(_rarity2.rare == _rarity3.rare, "Inconsisten rarity"); 111 | require(_rarity3.rare == _rarity1.rare, "Inconsisten rarity"); 112 | } 113 | function _isWeapon( 114 | BattleHeroData.DeconstructedGen memory deconstructed 115 | ) internal pure returns (bool){ 116 | return deconstructed._type > 49; 117 | } 118 | function _uintToRarity(uint _rarity) public pure returns(IBattleHeroGenScience.Rarity){ 119 | if(_rarity == 0){ 120 | return IBattleHeroGenScience.Rarity.COMMON; 121 | } 122 | if(_rarity == 1){ 123 | return IBattleHeroGenScience.Rarity.LOW_RARE; 124 | } 125 | if(_rarity == 2){ 126 | return IBattleHeroGenScience.Rarity.RARE; 127 | } 128 | if(_rarity == 3){ 129 | return IBattleHeroGenScience.Rarity.EPIC; 130 | } 131 | if(_rarity == 4){ 132 | return IBattleHeroGenScience.Rarity.LEGEND; 133 | } 134 | if(_rarity == 5){ 135 | return IBattleHeroGenScience.Rarity.MITIC; 136 | } 137 | return IBattleHeroGenScience.Rarity.COMMON; 138 | } 139 | function _uint2str(uint _i) internal pure returns (string memory _uintAsString) { 140 | if (_i == 0) { 141 | return "0"; 142 | } 143 | uint j = _i; 144 | uint len; 145 | while (j != 0) { 146 | len++; 147 | j /= 10; 148 | } 149 | bytes memory bstr = new bytes(len); 150 | uint k = len; 151 | while (_i != 0) { 152 | k = k-1; 153 | uint8 temp = (48 + uint8(_i - _i / 10 * 10)); 154 | bytes1 b1 = bytes1(temp); 155 | bstr[k] = b1; 156 | _i /= 10; 157 | } 158 | return string(bstr); 159 | } 160 | function _append(string memory a, string memory b) internal pure returns (string memory) { 161 | return string(abi.encodePacked(a, b)); 162 | } 163 | function _padLeft(uint256 r0) internal pure returns(string memory){ 164 | string memory appended = ""; 165 | if(r0 < 10){ 166 | appended = _append("0" , _uint2str(r0)); 167 | }else{ 168 | appended = _uint2str(r0); 169 | } 170 | return appended; 171 | } 172 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |