// File: contracts/lib/RandomNumber.sol
pragma solidity 0.8.2;
library RandomNumber {
function randomNum(uint256 seed) internal returns (uint256) {
uint256 _number =
(uint256(
keccak256(abi.encodePacked(blockhash(block.number - 1), seed))
) % 100);
if (_number <= 0) {
_number = 1;
}
return _number;
}
function rand1To10(uint256 seed) internal returns (uint256) {
uint256 _number =
(uint256(
keccak256(abi.encodePacked(blockhash(block.number - 1), seed))
) % 10);
if (_number <= 0) {
_number = 10;
}
return _number;
}
function randDecimal(uint256 seed) internal returns (uint256) {
return (rand1To10(seed) / 10);
}
function randomNumberToMax(uint256 seed, uint256 max)
internal
returns (uint256)
{
return (uint256(
keccak256(abi.encodePacked(blockhash(block.number - 1), seed))
) % max);
}
function randomNumber1ToMax(uint256 seed, uint256 max)
internal
returns (uint256)
{
uint256 _number =
(uint256(
keccak256(abi.encodePacked(blockhash(block.number - 1), seed))
) % max);
if (_number <= 0) {
_number = max;
}
return _number;
}
}
// File: contracts/base/Ownable.sol
pragma solidity 0.8.2;
contract Ownable {
address public owner;
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function transferOwnership(address newOwner) external onlyOwner {
if (newOwner != address(0)) {
owner = newOwner;
}
}
}
// File: contracts/fighter/FighterConfig.sol
pragma solidity 0.8.2;
contract FighterConfig is Ownable {
uint256 public currentFighterCost = 50000000000000000 wei;
string public constant LEGENDARY = "legendary";
string public constant EPIC = "epic";
string public constant RARE = "rare";
string public constant UNCOMMON = "uncommon";
string public constant COMMON = "common";
// actually 1 higher than real life because of the issue with a 0 index fighter
uint256 public maxFighters = 6561;
uint256 public maxLegendaryFighters = 1;
uint256 public maxEpicFighters = 5;
uint256 public maxRareFighters = 25;
uint256 public maxUncommonFighters = 125;
uint256 public maxCommonFighters = 500;
uint256 public maxFightersPerChar = 656;
string public tokenMetadataEndpoint =
"https://cryptobrawle.rs/api/getFighterInfo/";
bool public isTrainingEnabled = false;
uint256 public trainingFactor = 3;
uint256 public trainingCost = 5000000000000000 wei; // cost of training in wei
function setTrainingFactor(uint256 newFactor) external onlyOwner {
trainingFactor = newFactor;
}
function setNewTrainingCost(uint256 newCost) external onlyOwner {
trainingCost = newCost;
}
function enableTraining() external onlyOwner {
isTrainingEnabled = true;
}
}
// File: contracts/fighter/FighterBase.sol
pragma solidity 0.8.2;
contract FighterBase is FighterConfig {
/*** EVENTS ***/
event Transfer(
address indexed from,
address indexed to,
uint256 indexed tokenId
);
event Creation(
address owner,
uint256 fighterId,
uint256 maxHealth,
uint256 speed,
uint256 strength,
string rarity,
string name,
string imageHash,
uint256 mintNum
);
event AttributeIncrease(
address owner,
uint256 fighterId,
string attribute,
uint256 increaseValue
);
event Healed(address owner, uint256 fighterId, uint256 maxHealth);
struct Fighter {
uint256 maxHealth;
uint256 health;
uint256 speed;
uint256 strength;
string name;
string rarity;
string image;
uint256 mintNum;
}
/*** STORAGE ***/
Fighter[] fighters;
mapping(uint256 => address) public fighterIdToOwner; // lookup for owner of a specific fighter
mapping(uint256 => address) public fighterIdToApproved; // Shows appoved address for sending of fighters, Needed for ERC721
mapping(address => address[]) public ownerToOperators;
mapping(address => uint256) internal ownedFightersCount;
string[] public availableFighterNames;
mapping(string => uint256) public indexOfAvailableFighterName;
mapping(string => uint256) public rarityToSkillBuff;
mapping(string => uint256) public fighterNameToMintedCount;
mapping(string => mapping(string => string))
public fighterNameToRarityImageHashes;
mapping(string => mapping(string => uint256))
public fighterNameToRarityCounts;
function getMintedCountForFighterRarity(
string memory _fighterName,
string memory _fighterRarity
) external view returns (uint256 mintedCount) {
return fighterNameToRarityCounts[_fighterName][_fighterRarity];
}
function addFighterCharacter(
string memory newName,
string memory legendaryImageHash,
string memory epicImageHash,
string memory rareImageHash,
string memory uncommonImageHash,
string memory commonImageHash
) external onlyOwner {
indexOfAvailableFighterName[newName] = availableFighterNames.length;
availableFighterNames.push(newName);
fighterNameToMintedCount[newName] = 0;
fighterNameToRarityImageHashes[newName][LEGENDARY] = legendaryImageHash;
fighterNameToRarityImageHashes[newName][EPIC] = epicImageHash;
fighterNameToRarityImageHashes[newName][RARE] = rareImageHash;
fighterNameToRarityImageHashes[newName][UNCOMMON] = uncommonImageHash;
fighterNameToRarityImageHashes[newName][COMMON] = commonImageHash;
fighterNameToRarityCounts[newName][LEGENDARY] = 0;
fighterNameToRarityCounts[newName][EPIC] = 0;
fighterNameToRarityCounts[newName][RARE] = 0;
fighterNameToRarityCounts[newName][UNCOMMON] = 0;
fighterNameToRarityCounts[newName][COMMON] = 0;
}
/// @dev Checks if a given address is the current owner of a particular fighter.
/// @param _claimant the address we are validating against.
/// @param _tokenId fighter id, only valid when > 0
function _owns(address _claimant, uint256 _tokenId)
internal
view
returns (bool)
{
return fighterIdToOwner[_tokenId] == _claimant;
}
function _transfer(
address _from,
address _to,
uint256 _fighterId
) internal {
fighterIdToOwner[_fighterId] = _to;
ownedFightersCount[_to]++;
// Check that it isn't a newly created fighter before messing with ownership values
if (_from != address(0)) {
// Remove any existing approvals for the token
fighterIdToApproved[_fighterId] = address(0);
ownedFightersCount[_from]--;
}
// Emit the transfer event.
emit Transfer(_from, _to, _fighterId);
}
function _createFighter(
uint256 _maxHealth,
uint256 _speed,
uint256 _strength,
address _owner,
string memory _rarity,
string memory _name,
uint256 _mintNum
) internal returns (uint256) {
string memory _fighterImage =
fighterNameToRarityImageHashes[_name][_rarity];
Fighter memory _fighter =
Fighter({
maxHealth: _maxHealth,
health: _maxHealth, // Fighters are always created with maximum health
speed: _speed,
strength: _strength,
name: _name,
rarity: _rarity,
image: _fighterImage,
mintNum: _mintNum
});
uint256 newFighterId = fighters.length;
fighters.push(_fighter);
emit Creation(
_owner,
newFighterId,
_maxHealth,
_speed,
_strength,
_rarity,
_name,
_fighterImage,
_mintNum
);
// This will assign ownership, and also emit the Transfer event as
// per ERC721 draft
_transfer(address(0), _owner, newFighterId);
return newFighterId;
}
function _updateFighterInStorage(
Fighter memory _updatedFighter,
uint256 _fighterId
) internal {
fighters[_fighterId] = _updatedFighter;
}
function _trainSpeed(
uint256 _fighterId,
uint256 _attributeIncrease,
address _owner
) internal {
Fighter memory _fighter = fighters[_fighterId];
_fighter.speed += _attributeIncrease;
_updateFighterInStorage(_fighter, _fighterId);
emit AttributeIncrease(_owner, _fighterId, "speed", _attributeIncrease);
}
function _trainStrength(
uint256 _fighterId,
uint256 _attributeIncrease,
address _owner
) internal {
Fighter memory _fighter = fighters[_fighterId];
_fighter.strength += _attributeIncrease;
_updateFighterInStorage(_fighter, _fighterId);
emit AttributeIncrease(
_owner,
_fighterId,
"strength",
_attributeIncrease
);
}
}
// File: contracts/marketplace/MarketplaceConfig.sol
pragma solidity 0.8.2;
contract MarketplaceConfig is Ownable, FighterBase {
uint256 public marketplaceCut = 5;
struct Combatant {
uint256 fighterId;
Fighter fighter;
uint256 damageModifier;
}
struct Sale {
uint256 fighterId;
uint256 price;
}
mapping(uint256 => Sale) public fighterIdToSale; // Storing of figher Ids against their sale Struct
mapping(uint256 => uint256) public fighterIdToBrawl; // Map of fighter Ids to their max health
event PurchaseSuccess(
address buyer,
uint256 price,
uint256 fighterId,
address seller
);
event FightComplete(
address winner,
uint256 winnerId,
address loser,
uint256 loserId
);
event MarketplaceRemoval(address owner, uint256 fighterId);
event ArenaRemoval(address owner, uint256 fighterId);
event MarketplaceAdd(address owner, uint256 fighterId, uint256 price);
event ArenaAdd(address owner, uint256 fighterId);
function setNewMarketplaceCut(uint256 _newCut) external onlyOwner {
marketplaceCut = _newCut;
}
function withdrawBalance() external onlyOwner {
payable(owner).transfer(address(this).balance);
}
function withdrawBalanceToAddress(address _recipient) external onlyOwner {
payable(_recipient).transfer(address(this).balance);
}
function killContract() external onlyOwner {
selfdestruct(payable(owner));
}
function _calculateCut(uint256 _totalPrice) internal returns (uint256) {
return ((_totalPrice / 100) * marketplaceCut);
}
function _fighterIsForSale(uint256 _fighterId) internal returns (bool) {
return (fighterIdToSale[_fighterId].price > 0);
}
function _fighterIsForBrawl(uint256 _fighterId) internal returns (bool) {
return (fighterIdToBrawl[_fighterId] > 0);
}
function _removeFighterFromSale(uint256 _fighterId) internal {
delete fighterIdToSale[_fighterId];
}
function _removeFighterFromArena(uint256 _fighterId) internal {
delete fighterIdToBrawl[_fighterId];
}
}
// File: contracts/marketplace/Marketplace.sol
pragma solidity 0.8.2;
contract Marketplace is MarketplaceConfig {
function getPriceForFighter(uint256 _fighterId) external returns (uint256) {
return fighterIdToSale[_fighterId].price;
}
function removeFighterFromSale(uint256 _fighterId) external {
require(_owns(msg.sender, _fighterId));
// Just double check we can actually remove a fighter before we go any further
require(_fighterIsForSale(_fighterId));
_removeFighterFromSale(_fighterId);
emit MarketplaceRemoval(msg.sender, _fighterId);
}
function removeFighterFromArena(uint256 _fighterId) external {
require(_owns(msg.sender, _fighterId));
// Just double check we can actually remove a fighter before we go any further
require(_fighterIsForBrawl(_fighterId));
_removeFighterFromArena(_fighterId);
emit ArenaRemoval(msg.sender, _fighterId);
}
function makeFighterAvailableForSale(uint256 _fighterId, uint256 _price)
external
{
require(_owns(msg.sender, _fighterId));
// Fighters can't be both for sale and open for brawling
require(!_fighterIsForBrawl(_fighterId));
require(_price > 0);
// Double check there is not an existing third party transfer approval
require(fighterIdToApproved[_fighterId] == address(0));
fighterIdToSale[_fighterId] = Sale({
fighterId: _fighterId,
price: _price
});
emit MarketplaceAdd(msg.sender, _fighterId, _price);
}
function makeFighterAvailableForBrawl(uint256 _fighterId) external {
require(_owns(msg.sender, _fighterId));
// Fighters can't be both for sale and open for brawling
require(!_fighterIsForSale(_fighterId));
// We don't want fighters being added twice
require(!_fighterIsForBrawl(_fighterId));
// Double check there is not an existing third party transfer approval
require(fighterIdToApproved[_fighterId] == address(0));
fighterIdToBrawl[_fighterId] = _fighterId;
emit ArenaAdd(msg.sender, _fighterId);
}
function buyFighter(uint256 _fighterId) external payable {
address _seller = fighterIdToOwner[_fighterId];
_makePurchase(_fighterId, msg.value);
_transfer(_seller, msg.sender, _fighterId);
emit PurchaseSuccess(msg.sender, msg.value, _fighterId, _seller);
}
function _strike(
uint256 _attackerId,
uint256 _defenderId,
uint256 _attackerStrength,
uint256 _defenderStrength,
uint256 _seed
) internal returns (bool) {
uint256 _attackerAttackRoll =
RandomNumber.randomNumber1ToMax(_seed, 20) + _attackerStrength;
uint256 _defenderDefenseRoll =
RandomNumber.randomNumber1ToMax(_seed * 3, 20) + _defenderStrength;
if (_attackerAttackRoll >= _defenderDefenseRoll) {
return true;
}
return false;
}
function _performFight(
uint256 _attackerId,
uint256 _defenderId,
Fighter memory _attacker,
Fighter memory _defender,
uint256 _seed
) internal returns (uint256 winnerId, uint256 loserId) {
uint256 _generatedSeed =
RandomNumber.randomNumber1ToMax(_seed, 99999999);
uint256 _totalSpeed = _attacker.speed + _defender.speed;
uint256 _attackerSpeedRoll =
RandomNumber.randomNumber1ToMax(_seed, 20) + _attacker.speed;
uint256 _defenderSpeedRoll =
RandomNumber.randomNumber1ToMax(_generatedSeed, 20) +
_defender.speed;
bool _attackerIsStrikingFirst =
_attackerSpeedRoll >= _defenderSpeedRoll;
if (_attackerIsStrikingFirst) {
if (
_strike(
_attackerId,
_defenderId,
_attacker.strength,
_defender.strength,
_seed * 2
)
) {
return (_attackerId, _defenderId);
}
} else {
if (
_strike(
_defenderId,
_attackerId,
_defender.strength,
_attacker.strength,
_generatedSeed * 2
)
) {
return (_defenderId, _attackerId);
}
}
if (_attackerIsStrikingFirst) {
if (
_strike(
_defenderId,
_attackerId,
_defender.strength,
_attacker.strength,
_generatedSeed * 3
)
) {
return (_defenderId, _attackerId);
}
} else {
if (
_strike(
_attackerId,
_defenderId,
_attacker.strength,
_defender.strength,
_seed * 3
)
) {
return (_attackerId, _defenderId);
}
}
uint256 _defenderEndCheck =
_defender.speed +
_defender.strength +
RandomNumber.randomNumber1ToMax(_generatedSeed, 20);
uint256 _attackerEndCheck =
_attacker.speed +
_attacker.strength +
RandomNumber.randomNumber1ToMax(_seed, 20);
if (_defenderEndCheck >= _attackerEndCheck) {
return (_defenderId, _attackerId);
}
return (_attackerId, _defenderId);
}
function fight(
uint256 _attackerId,
uint256 _defenderId,
uint256 _seed
) external {
Fighter memory _attacker = fighters[_attackerId];
Fighter memory _defender = fighters[_defenderId];
// fighter actually in the arena is always the defender
require(_fighterIsForBrawl(_defenderId));
// Make sure the challenger is actually sending the transaction
require(_owns(msg.sender, _attackerId));
// Also make sure that the challenger is not attacking his own fighter
require(!_owns(msg.sender, _defenderId));
// Ensure that a 'stronger' fighter is not attacking a 'weaker' fighter
require(
(_attacker.speed + _attacker.strength) <=
(_defender.speed + _defender.strength)
);
(uint256 _winnerId, uint256 _loserId) =
_performFight(
_attackerId,
_defenderId,
_attacker,
_defender,
_seed
);
if (_fighterIsForBrawl(_winnerId)) {
_removeFighterFromArena(_winnerId);
} else {
_removeFighterFromArena(_loserId);
}
address _winnerAddress = fighterIdToOwner[_winnerId];
address _loserAddress = fighterIdToOwner[_loserId];
_transfer(_loserAddress, _winnerAddress, _loserId);
emit FightComplete(_winnerAddress, _winnerId, _loserAddress, _loserId);
}
function _makePurchase(uint256 _fighterId, uint256 _price) internal {
require(!_owns(msg.sender, _fighterId));
require(_fighterIsForSale(_fighterId));
require(_price >= fighterIdToSale[_fighterId].price);
address sellerAddress = fighterIdToOwner[_fighterId];
_removeFighterFromSale(_fighterId);
uint256 saleCut = _calculateCut(_price);
uint256 totalSale = _price - saleCut;
payable(sellerAddress).transfer(totalSale);
}
}
// File: contracts/lib/Integers.sol
pragma solidity 0.8.2;
library Integers {
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
}
// File: contracts/base/ERC721.sol
pragma solidity 0.8.2;
abstract contract ERC721 {
// Required methods
function totalSupply() public view virtual returns (uint256 total) {}
function balanceOf(address _owner)
public
view
virtual
returns (uint256 balance)
{}
function ownerOf(uint256 _tokenId)
external
view
virtual
returns (address owner)
{}
function approve(address _to, uint256 _tokenId) external virtual {}
function transfer(address _to, uint256 _tokenId) external virtual {}
function tokenURI(uint256 _tokenId)
external
view
virtual
returns (string memory _tokenURI)
{}
function baseURI() external view virtual returns (string memory _baseURI) {}
function transferFrom(
address _from,
address _to,
uint256 _tokenId
) external virtual {}
function getApproved(uint256 _tokenId)
external
virtual
returns (address _approvedAddress)
{}
function setApprovalForAll(address _to, bool approved) external virtual {}
function isApprovedForAll(address _owner, address _operator)
external
virtual
returns (bool isApproved)
{}
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
) external virtual {}
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes calldata _data
) external virtual {}
// Events
event Approval(
address indexed owner,
address indexed approved,
uint256 indexed tokenId
);
event ApprovalForAll(
address indexed owner,
address indexed operator,
bool approved
);
function _isContract(address _addr)
internal
view
returns (bool isContract)
{
uint32 size;
assembly {
size := extcodesize(_addr)
}
return (size > 0);
}
// ERC-165 Compatibility (https://github.com/ethereum/EIPs/issues/165)
function supportsInterface(bytes4 _interfaceID)
external
view
virtual
returns (bool)
{}
/// @notice Handle the receipt of an NFT
/// @dev The ERC721 smart contract calls this function on the
/// recipient after a `transfer`. This function MAY throw to revert and reject the transfer. Return
/// of other than the magic value MUST result in the transaction being reverted.
/// @notice The contract address is always the message sender.
/// @param _operator The address which called `safeTransferFrom` function
/// @param _from The address which previously owned the token
/// @param _tokenId The NFT identifier which is being transferred
/// @param _data Additional data with no specified format
/// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
/// unless throwing
function onERC721Received(
address _operator,
address _from,
uint256 _tokenId,
bytes calldata _data
) external virtual returns (bytes4) {}
}
// File: contracts/base/Priced.sol
pragma solidity 0.8.2;
contract Priced {
modifier costs(uint256 price) {
if (msg.value >= price) {
_;
}
}
}
// File: contracts/base/Pausable.sol
pragma solidity 0.8.2;
contract Pausable is Ownable {
bool public isPaused = false;
modifier whenNotPaused() {
require(!isPaused);
_;
}
function pause() external onlyOwner {
isPaused = true;
}
function unPause() external onlyOwner {
isPaused = false;
}
}
// File: contracts/base/IERC721Receiver.sol
pragma solidity ^0.8.2;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
// File: contracts/fighter/FighterTraining.sol
pragma solidity 0.8.2;
contract FighterTraining is FighterBase {
function _train(
uint256 _fighterId,
string memory _attribute,
uint256 _attributeIncrease
) internal {
if (
keccak256(abi.encodePacked(_attribute)) ==
keccak256(abi.encodePacked("strength"))
) {
_trainStrength(_fighterId, _attributeIncrease, msg.sender);
} else if (
keccak256(abi.encodePacked(_attribute)) ==
keccak256(abi.encodePacked("speed"))
) {
_trainSpeed(_fighterId, _attributeIncrease, msg.sender);
}
}
}
// File: contracts/fighter/FighterOwnership.sol
pragma solidity 0.8.2;
contract FighterOwnership is
FighterConfig,
FighterBase,
FighterTraining,
ERC721,
Priced,
Pausable,
MarketplaceConfig
{
using Integers for uint256;
/// @notice Name and symbol of the non fungible token, as defined in ERC721.
string public constant name = "CryptoBrawlers";
string public constant symbol = "BRAWLER";
bytes4 constant ERC721_RECEIVED = 0xf0b9e5ba;
bytes4 constant InterfaceSignature_ERC165 =
bytes4(keccak256("supportsInterface(bytes4)"));
/*
* bytes4(keccak256('balanceOf(address)')) == 0x70a08231
* bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
* bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
* bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
* bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
* bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
* bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
* bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
* bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
*
* => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
* 0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
*/
bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
/*
* bytes4(keccak256('name()')) == 0x06fdde03
* bytes4(keccak256('symbol()')) == 0x95d89b41
* bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
*
* => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
*/
bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
/// @notice Introspection interface as per ERC-165 (https://github.com/ethereum/EIPs/issues/165).
/// Returns true for any standardized interfaces implemented by this contract. We implement
/// ERC-165 (obviously!) and ERC-721.
function supportsInterface(bytes4 _interfaceID)
external
view
override
returns (bool)
{
return ((_interfaceID == InterfaceSignature_ERC165) ||
(_interfaceID == _INTERFACE_ID_ERC721) ||
(_interfaceID == _INTERFACE_ID_ERC721_METADATA));
}
function onERC721Received(
address _operator,
address _from,
uint256 _tokenId,
bytes calldata _data
) external pure override returns (bytes4) {
revert();
}
// Internal utility functions: These functions all assume that their input arguments
// are valid. We leave it to public methods to sanitize their inputs and follow
// the required logic.
/// @dev Checks if a given address currently has transferApproval for a particular fighter.
/// @param _claimant the address we are confirming brawler is approved for.
/// @param _tokenId fighter id, only valid when > 0
function _approvedFor(address _claimant, uint256 _tokenId)
internal
view
returns (bool)
{
if (fighterIdToApproved[_tokenId] == _claimant) {
return true;
}
bool _senderIsOperator = false;
address _owner = fighterIdToOwner[_tokenId];
address[] memory _validOperators = ownerToOperators[_owner];
uint256 _operatorIndex;
for (
_operatorIndex = 0;
_operatorIndex < _validOperators.length;
_operatorIndex++
) {
if (_validOperators[_operatorIndex] == _claimant) {
_senderIsOperator = true;
break;
}
}
return _senderIsOperator;
}
/// @dev Marks an address as being approved for transferFrom(), overwriting any previous
/// approval. Setting _approved to address(0) clears all transfer approval.
/// NOTE: _approve() does NOT send the Approval event.
function _approve(uint256 _tokenId, address _approved) internal {
fighterIdToApproved[_tokenId] = _approved;
}
/// @notice Returns the number of Fighters owned by a specific address.
/// @param _owner The owner address to check.
/// @dev Required for ERC-721 compliance
function balanceOf(address _owner)
public
view
override
returns (uint256 count)
{
require(_owner != address(0));
return ownedFightersCount[_owner];
}
/// @notice Transfers a Fighter to another address. If transferring to a smart
/// contract be VERY CAREFUL to ensure that it is aware of ERC-721.
/// @param _to The address of the recipient, can be a user or contract.
/// @param _tokenId The ID of the fighter to transfer.
/// @dev Required for ERC-721 compliance.
function transfer(address _to, uint256 _tokenId) external override {
// Safety check to prevent against an unexpected 0x0 default.
require(_to != address(0));
// Disallow transfers to this contract to prevent accidental misuse.
require(_to != address(this));
// You can only send your own fighter.
require(_owns(msg.sender, _tokenId));
// If transferring we can't keep a fighter in the arena...
if (_fighterIsForBrawl(_tokenId)) {
_removeFighterFromArena(_tokenId);
emit ArenaRemoval(msg.sender, _tokenId);
}
// ...nor can they be in our marketplace.
if (_fighterIsForSale(_tokenId)) {
_removeFighterFromSale(_tokenId);
emit MarketplaceRemoval(msg.sender, _tokenId);
}
// Reassign ownership, clear pending approvals, emit Transfer event.
_transfer(msg.sender, _to, _tokenId);
}
/// @notice Grant another address the right to transfer a specific fighter via
/// transferFrom(). This is the preferred flow for transfering NFTs to contracts.
/// @param _to The address to be granted transfer approval. Pass address(0) to
/// clear all approvals.
/// @param _tokenId The ID of the fighter that can be transferred if this call succeeds.
/// @dev Required for ERC-721 compliance.
function approve(address _to, uint256 _tokenId) external override {
// Only an owner can grant transfer approval.
require(_owns(msg.sender, _tokenId));
// If selling on an external marketplace we can't keep a fighter in the arena...
if (_fighterIsForBrawl(_tokenId)) {
_removeFighterFromArena(_tokenId);
emit ArenaRemoval(msg.sender, _tokenId);
}
// ...nor can they be in our marketplace.
if (_fighterIsForSale(_tokenId)) {
_removeFighterFromSale(_tokenId);
emit MarketplaceRemoval(msg.sender, _tokenId);
}
// Register the approval (replacing any previous approval).
_approve(_tokenId, _to);
// Emit approval event.
emit Approval(msg.sender, _to, _tokenId);
}
/// @notice Transfer a fighter owned by another address, for which the calling address
/// has previously been granted transfer approval by the owner.
/// @param _from The address that owns the fighter to be transfered.
/// @param _to The address that should take ownership of the fighter. Can be any address,
/// including the caller.
/// @param _tokenId The ID of the fighter to be transferred.
/// @dev Required for ERC-721 compliance.
function transferFrom(
address _from,
address _to,
uint256 _tokenId
) external override {
// Safety check to prevent against an unexpected 0x0 default.
require(_to != address(0));
// Disallow transfers to this contract to prevent accidental misuse.
require(_to != address(this));
// Check for approval and valid ownership
require(_approvedFor(msg.sender, _tokenId));
require(_owns(_from, _tokenId));
// This should never be the case, but might as well check
if (_fighterIsForBrawl(_tokenId)) {
_removeFighterFromArena(_tokenId);
emit ArenaRemoval(msg.sender, _tokenId);
}
// ...nor can they be in our marketplace.
if (_fighterIsForSale(_tokenId)) {
_removeFighterFromSale(_tokenId);
emit MarketplaceRemoval(msg.sender, _tokenId);
}
// Reassign ownership (also clears pending approvals and emits Transfer event).
_transfer(_from, _to, _tokenId);
// Remove an existing external approval to move the fighter.
_approve(_tokenId, address(0));
}
function _safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
) internal {
// This should never be the case, but might as well check
if (_fighterIsForBrawl(_tokenId)) {
_removeFighterFromArena(_tokenId);
emit ArenaRemoval(msg.sender, _tokenId);
}
// ...nor can they be in our marketplace.
if (_fighterIsForSale(_tokenId)) {
_removeFighterFromSale(_tokenId);
emit MarketplaceRemoval(msg.sender, _tokenId);
}
// Reassign ownership (also clears pending approvals and emits Transfer event).
_transfer(_from, _to, _tokenId);
// Remove an existing external approval to move the fighter.
_approve(_tokenId, address(0));
}
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId
) external override {
// Safety check to prevent against an unexpected 0x0 default.
require(_to != address(0));
// Disallow transfers to this contract to prevent accidental misuse.
require(_to != address(this));
// Check for approval and valid ownership
require(_approvedFor(msg.sender, _tokenId));
require(_owns(_from, _tokenId));
_safeTransferFrom(_from, _to, _tokenId);
if (_isContract(_to)) {
bytes4 retval =
IERC721Receiver(_to).onERC721Received(_from, _to, _tokenId, "");
require(ERC721_RECEIVED == retval);
}
}
function safeTransferFrom(
address _from,
address _to,
uint256 _tokenId,
bytes calldata _data
) external override {
// Safety check to prevent against an unexpected 0x0 default.
require(_to != address(0));
// Disallow transfers to this contract to prevent accidental misuse.
require(_to != address(this));
// Check for approval and valid ownership
require(_approvedFor(msg.sender, _tokenId));
require(_owns(_from, _tokenId));
_safeTransferFrom(_from, _to, _tokenId);
if (_isContract(_to)) {
bytes4 retval =
IERC721Receiver(_to).onERC721Received(
_from,
_to,
_tokenId,
_data
);
require(ERC721_RECEIVED == retval);
}
}
function getApproved(uint256 _tokenId)
external
view
override
returns (address _approvedAddress)
{
return fighterIdToApproved[_tokenId];
}
function setApprovalForAll(address _to, bool _approved) external override {
address[] memory _operatorsForSender = ownerToOperators[msg.sender];
if (_approved) {
ownerToOperators[msg.sender].push(_to);
}
if (!_approved) {
if (ownerToOperators[msg.sender].length == 0) {
emit ApprovalForAll(msg.sender, _to, false);
return;
}
uint256 _operatorIndex;
for (
_operatorIndex = 0;
_operatorIndex < _operatorsForSender.length;
_operatorIndex++
) {
if (ownerToOperators[msg.sender][_operatorIndex] == _to) {
ownerToOperators[msg.sender][
_operatorIndex
] = ownerToOperators[msg.sender][
ownerToOperators[msg.sender].length - 1
];
ownerToOperators[msg.sender].pop();
break;
}
}
}
emit ApprovalForAll(msg.sender, _to, _approved);
}
function isApprovedForAll(address _owner, address _operator)
external
view
override
returns (bool isApproved)
{
address[] memory _operatorsForSender = ownerToOperators[_owner];
if (_operatorsForSender.length == 0) {
return false;
}
bool _isApproved = true;
uint256 _operatorIndex;
for (
_operatorIndex = 0;
_operatorIndex < _operatorsForSender.length;
_operatorIndex++
) {
if (_operatorsForSender[_operatorIndex] != _operator) {
_isApproved = false;
break;
}
}
return _isApproved;
}
/// @notice Returns the total number of fighters currently in existence.
/// @dev Required for ERC-721 compliance.
function totalSupply() public view override returns (uint256) {
return fighters.length - 1; // -1 because of the phantom 0 index fighter that doesn't play nicely
}
/// @notice Returns the address currently assigned ownership of a given fighter.
/// @dev Required for ERC-721 compliance.
function ownerOf(uint256 _tokenId)
external
view
override
returns (address owner)
{
owner = fighterIdToOwner[_tokenId];
require(owner != address(0));
return owner;
}
function tokenURI(uint256 _tokenId)
external
view
override
returns (string memory)
{
return
string(
abi.encodePacked(tokenMetadataEndpoint, _tokenId.toString())
);
}
function baseURI() external view override returns (string memory) {
return tokenMetadataEndpoint;
}
modifier currentFighterPrice() {
require(msg.value >= currentFighterCost);
_;
}
function trainFighter(
uint256 _fighterId,
string memory _attribute,
uint256 _seed
) external payable costs(trainingCost) returns (uint256 _increaseValue) {
require(isTrainingEnabled);
require(_owns(msg.sender, _fighterId));
uint256 _attributeIncrease =
(RandomNumber.rand1To10(_seed) / trainingFactor);
if (_attributeIncrease == 0) {
_attributeIncrease = 1;
}
_train(_fighterId, _attribute, _attributeIncrease);
return _attributeIncrease;
}
function _getFighterRarity(uint256 _seed, string memory _fighterName)
internal
returns (string memory)
{
uint256 _rarityRoll =
RandomNumber.randomNumber1ToMax(_seed, maxFightersPerChar);
uint256 _minEpicRoll =
maxFightersPerChar - (maxEpicFighters + maxLegendaryFighters);
uint256 _minRareRoll =
maxFightersPerChar -
(maxRareFighters + maxEpicFighters + maxLegendaryFighters);
uint256 _minUncommonRoll =
maxFightersPerChar -
(maxUncommonFighters +
maxRareFighters +
maxEpicFighters +
maxLegendaryFighters);
if (
fighterNameToRarityCounts[_fighterName][LEGENDARY] <
maxLegendaryFighters &&
_rarityRoll == maxFightersPerChar
) {
return LEGENDARY;
}
if (
fighterNameToRarityCounts[_fighterName][EPIC] < maxEpicFighters &&
_rarityRoll >= _minEpicRoll
) {
return EPIC;
}
if (
fighterNameToRarityCounts[_fighterName][RARE] < maxRareFighters &&
_rarityRoll >= _minRareRoll
) {
return RARE;
}
if (
fighterNameToRarityCounts[_fighterName][UNCOMMON] <
maxUncommonFighters &&
_rarityRoll >= _minUncommonRoll
) {
return UNCOMMON;
}
if (
fighterNameToRarityCounts[_fighterName][COMMON] <
maxCommonFighters &&
_rarityRoll >= 1
) {
return COMMON;
}
string[] memory _leftoverRarities;
if (
fighterNameToRarityCounts[_fighterName][LEGENDARY] <
maxLegendaryFighters
) {
_leftoverRarities[_leftoverRarities.length] = LEGENDARY;
}
if (fighterNameToRarityCounts[_fighterName][EPIC] < maxEpicFighters) {
_leftoverRarities[_leftoverRarities.length] = EPIC;
}
if (fighterNameToRarityCounts[_fighterName][RARE] < maxRareFighters) {
_leftoverRarities[_leftoverRarities.length] = RARE;
}
if (
fighterNameToRarityCounts[_fighterName][UNCOMMON] <
maxUncommonFighters
) {
_leftoverRarities[_leftoverRarities.length] = UNCOMMON;
}
if (
fighterNameToRarityCounts[_fighterName][COMMON] < maxCommonFighters
) {
_leftoverRarities[_leftoverRarities.length] = COMMON;
}
if (_leftoverRarities.length == 1) {
return _leftoverRarities[0];
}
uint256 _leftoverRoll =
RandomNumber.randomNumberToMax(_seed, _leftoverRarities.length);
return _leftoverRarities[_leftoverRoll];
}
function _getFighterName(uint256 _seed)
internal
returns (string memory _fighterName)
{
uint256 _nameIndex =
RandomNumber.randomNumberToMax(_seed, availableFighterNames.length); // Use the whole array length because the random max number does not include the top end
return availableFighterNames[_nameIndex];
}
function _removeNameFromAvailableNamesArray(string memory _fighterName)
internal
{
uint256 _nameIndex = indexOfAvailableFighterName[_fighterName];
require(
keccak256(abi.encodePacked(availableFighterNames[_nameIndex])) ==
keccak256(abi.encodePacked(_fighterName))
); // double check something wiggly hasn't happened
if (availableFighterNames.length > 1) {
availableFighterNames[_nameIndex] = availableFighterNames[
availableFighterNames.length - 1
];
}
availableFighterNames.pop();
}
function searchForFighter(uint256 _seed)
external
payable
currentFighterPrice
whenNotPaused()
returns (uint256 newFighterId)
{
require(fighters.length < maxFighters);
string memory _fighterName = _getFighterName(_seed);
string memory _fighterRarity = _getFighterRarity(_seed, _fighterName);
uint256 _speed =
RandomNumber.rand1To10(_seed) + rarityToSkillBuff[_fighterRarity];
uint256 _strength =
RandomNumber.rand1To10(_speed + _seed) +
rarityToSkillBuff[_fighterRarity];
fighterNameToMintedCount[_fighterName] += 1;
fighterNameToRarityCounts[_fighterName][_fighterRarity] += 1;
uint256 _fighterId =
_createFighter(
10,
_speed,
_strength,
msg.sender,
_fighterRarity,
_fighterName,
fighterNameToRarityCounts[_fighterName][_fighterRarity]
);
if (fighterNameToMintedCount[_fighterName] >= maxFightersPerChar) {
_removeNameFromAvailableNamesArray(_fighterName);
}
uint256 _fighterCost = _getFighterCost();
if (_fighterCost > currentFighterCost) {
currentFighterCost = _fighterCost;
}
return _fighterId;
}
function _getFighterCost() internal returns (uint256 _cost) {
uint256 currentTotalFighters = fighters.length - 1;
if (currentTotalFighters < 500) {
return 50000000000000000 wei;
}
if (currentTotalFighters >= 500 && currentTotalFighters < 1000) {
return 100000000000000000 wei;
}
if (currentTotalFighters >= 1000 && currentTotalFighters < 1500) {
return 150000000000000000 wei;
}
if (currentTotalFighters >= 1500 && currentTotalFighters < 2000) {
return 200000000000000000 wei;
}
if (currentTotalFighters >= 2000 && currentTotalFighters < 2500) {
return 250000000000000000 wei;
}
if (currentTotalFighters >= 2500 && currentTotalFighters < 3000) {
return 300000000000000000 wei;
}
if (currentTotalFighters >= 3000 && currentTotalFighters < 3500) {
return 350000000000000000 wei;
}
if (currentTotalFighters >= 3500 && currentTotalFighters < 4000) {
return 400000000000000000 wei;
}
if (currentTotalFighters >= 4000 && currentTotalFighters < 4500) {
return 450000000000000000 wei;
}
if (currentTotalFighters >= 4500 && currentTotalFighters < 5000) {
return 500000000000000000 wei;
}
if (currentTotalFighters >= 5000 && currentTotalFighters < 5500) {
return 550000000000000000 wei;
}
if (currentTotalFighters >= 5500 && currentTotalFighters < 6000) {
return 600000000000000000 wei;
}
if (currentTotalFighters >= 6000) {
return 650000000000000000 wei;
}
return 650000000000000000 wei;
}
}
// File: contracts/CryptoBrawlers.sol
pragma solidity 0.8.2;
contract CryptoBrawlers is Marketplace, FighterOwnership {
constructor() {
rarityToSkillBuff[LEGENDARY] = 10;
rarityToSkillBuff[EPIC] = 5;
rarityToSkillBuff[RARE] = 3;
rarityToSkillBuff[UNCOMMON] = 1;
rarityToSkillBuff[COMMON] = 0;
fighters.push(); // phantom 0 index element in the fighters array to begin
}
function getInfoForFighter(uint256 _fighterId)
external
returns (
uint256 health,
uint256 speed,
uint256 strength,
string memory fighterName,
string memory image,
string memory rarity,
uint256 mintNum
)
{
Fighter memory _fighter = fighters[_fighterId];
return (
_fighter.health,
_fighter.speed,
_fighter.strength,
_fighter.name,
_fighter.image,
_fighter.rarity,
_fighter.mintNum
);
}
}
{
"compilationTarget": {
"CryptoBrawlers.sol": "CryptoBrawlers"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"fighterId","type":"uint256"}],"name":"ArenaAdd","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"fighterId","type":"uint256"}],"name":"ArenaRemoval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"fighterId","type":"uint256"},{"indexed":false,"internalType":"string","name":"attribute","type":"string"},{"indexed":false,"internalType":"uint256","name":"increaseValue","type":"uint256"}],"name":"AttributeIncrease","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"fighterId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxHealth","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"speed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"strength","type":"uint256"},{"indexed":false,"internalType":"string","name":"rarity","type":"string"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"imageHash","type":"string"},{"indexed":false,"internalType":"uint256","name":"mintNum","type":"uint256"}],"name":"Creation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"winner","type":"address"},{"indexed":false,"internalType":"uint256","name":"winnerId","type":"uint256"},{"indexed":false,"internalType":"address","name":"loser","type":"address"},{"indexed":false,"internalType":"uint256","name":"loserId","type":"uint256"}],"name":"FightComplete","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"fighterId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxHealth","type":"uint256"}],"name":"Healed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"fighterId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"MarketplaceAdd","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"fighterId","type":"uint256"}],"name":"MarketplaceRemoval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fighterId","type":"uint256"},{"indexed":false,"internalType":"address","name":"seller","type":"address"}],"name":"PurchaseSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"COMMON","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EPIC","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LEGENDARY","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RARE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNCOMMON","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"newName","type":"string"},{"internalType":"string","name":"legendaryImageHash","type":"string"},{"internalType":"string","name":"epicImageHash","type":"string"},{"internalType":"string","name":"rareImageHash","type":"string"},{"internalType":"string","name":"uncommonImageHash","type":"string"},{"internalType":"string","name":"commonImageHash","type":"string"}],"name":"addFighterCharacter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"availableFighterNames","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fighterId","type":"uint256"}],"name":"buyFighter","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"currentFighterCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enableTraining","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_attackerId","type":"uint256"},{"internalType":"uint256","name":"_defenderId","type":"uint256"},{"internalType":"uint256","name":"_seed","type":"uint256"}],"name":"fight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"fighterIdToApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"fighterIdToBrawl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"fighterIdToOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"fighterIdToSale","outputs":[{"internalType":"uint256","name":"fighterId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"fighterNameToMintedCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"}],"name":"fighterNameToRarityCounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"}],"name":"fighterNameToRarityImageHashes","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"_approvedAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fighterId","type":"uint256"}],"name":"getInfoForFighter","outputs":[{"internalType":"uint256","name":"health","type":"uint256"},{"internalType":"uint256","name":"speed","type":"uint256"},{"internalType":"uint256","name":"strength","type":"uint256"},{"internalType":"string","name":"fighterName","type":"string"},{"internalType":"string","name":"image","type":"string"},{"internalType":"string","name":"rarity","type":"string"},{"internalType":"uint256","name":"mintNum","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_fighterName","type":"string"},{"internalType":"string","name":"_fighterRarity","type":"string"}],"name":"getMintedCountForFighterRarity","outputs":[{"internalType":"uint256","name":"mintedCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fighterId","type":"uint256"}],"name":"getPriceForFighter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"indexOfAvailableFighterName","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"isApproved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTrainingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"killContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fighterId","type":"uint256"}],"name":"makeFighterAvailableForBrawl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fighterId","type":"uint256"},{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"makeFighterAvailableForSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marketplaceCut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxCommonFighters","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxEpicFighters","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxFighters","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxFightersPerChar","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLegendaryFighters","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxRareFighters","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxUncommonFighters","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"ownerToOperators","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"rarityToSkillBuff","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fighterId","type":"uint256"}],"name":"removeFighterFromArena","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fighterId","type":"uint256"}],"name":"removeFighterFromSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_seed","type":"uint256"}],"name":"searchForFighter","outputs":[{"internalType":"uint256","name":"newFighterId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCut","type":"uint256"}],"name":"setNewMarketplaceCut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCost","type":"uint256"}],"name":"setNewTrainingCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFactor","type":"uint256"}],"name":"setTrainingFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenMetadataEndpoint","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fighterId","type":"uint256"},{"internalType":"string","name":"_attribute","type":"string"},{"internalType":"uint256","name":"_seed","type":"uint256"}],"name":"trainFighter","outputs":[{"internalType":"uint256","name":"_increaseValue","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"trainingCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trainingFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"withdrawBalanceToAddress","outputs":[],"stateMutability":"nonpayable","type":"function"}]