Transaction Hash:
Block:
6721679 at Nov-17-2018 02:13:49 PM +UTC
Transaction Fee:
0.000696501 ETH
$1.37
Gas Used:
232,167 Gas / 3 Gwei
Emitted Events:
| 111 |
AdminUpgradeabilityProxy.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000fadae26458902e6eaf1415ec02151470a68f8137, 0x00000000000000000000000000000000000000000000000000000000000000c3 )
|
| 112 |
AdminUpgradeabilityProxy.0xef7878e56c319b18c7274f69dfa9e1fe9f0c506a36f37a6a24349f9c842f4a86( 0xef7878e56c319b18c7274f69dfa9e1fe9f0c506a36f37a6a24349f9c842f4a86, 0x000000000000000000000000fadae26458902e6eaf1415ec02151470a68f8137, 00000000000000000000000000000000000000000000000000000000000000d8, 00000000000000000000000000000000000000000000000000000000000000c3, 0000000000000000000000000000000000000000000000000000000000000003, 0000000000000000000000000000000000000000000000000000000000000006 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
|
0x5A0b54D5...D3E029c4c
Miner
| (Spark Pool) | 4,546.278951497786930781 Eth | 4,546.279647998786930781 Eth | 0.000696501 | |
| 0x9db37d15...465841038 | |||||
| 0xFaDaE264...0A68F8137 |
1.392033608350602067 Eth
Nonce: 4432
|
1.391337107350602067 Eth
Nonce: 4433
| 0.000696501 |
Execution Trace
AdminUpgradeabilityProxy.edb0d0b3( )
Weapons.claimWeaponOld( _chibiId=216 )-
ChibiFighters.ownerOf( _tokenId=216 ) => ( 0xFaDaE26458902e6eaf1415ec02151470A68F8137 )
-
ChibiFighters.queryChibi( _tokenId=216 ) => ( nameChibi=Super%20Chibi, infoUrl=https://chibigame.io/chibis.php?idj=216, dna=[31, 31, 3, 31, 31, 31, 31, 6, 0, 4, 4, 5, 0], father=0, mother=0, gen=0, adult=1525127704 )
-
File 1 of 3: AdminUpgradeabilityProxy
File 2 of 3: Weapons
File 3 of 3: ChibiFighters
pragma solidity ^0.4.24;
// File: contracts/upgradeability/Proxy.sol
/**
* @title Proxy
* @dev Implements delegation of calls to other contracts, with proper
* forwarding of return values and bubbling of failures.
* It defines a fallback function that delegates all calls to the address
* returned by the abstract _implementation() internal function.
*/
contract Proxy {
/**
* @dev Fallback function.
* Implemented entirely in `_fallback`.
*/
function () payable external {
_fallback();
}
/**
* @return The Address of the implementation.
*/
function _implementation() internal view returns (address);
/**
* @dev Delegates execution to an implementation contract.
* This is a low level function that doesn't return to its internal call site.
* It will return to the external caller whatever the implementation returns.
* @param implementation Address to delegate.
*/
function _delegate(address implementation) internal {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize)
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas, implementation, 0, calldatasize, 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize)
switch result
// delegatecall returns 0 on error.
case 0 { revert(0, returndatasize) }
default { return(0, returndatasize) }
}
}
/**
* @dev Function that is run as the first thing in the fallback function.
* Can be redefined in derived contracts to add functionality.
* Redefinitions must call super._willFallback().
*/
function _willFallback() internal {
}
/**
* @dev fallback implementation.
* Extracted to enable manual triggering.
*/
function _fallback() internal {
_willFallback();
_delegate(_implementation());
}
}
// File: openzeppelin-solidity/contracts/AddressUtils.sol
/**
* Utility library of inline functions on addresses
*/
library AddressUtils {
/**
* Returns whether the target address is a contract
* @dev This function will return false if invoked during the constructor of a contract,
* as the code is not actually created until after the constructor finishes.
* @param addr address to check
* @return whether the target address is a contract
*/
function isContract(address addr) internal view returns (bool) {
uint256 size;
// XXX Currently there is no better way to check if there is a contract in an address
// than to check the size of the code at that address.
// See https://ethereum.stackexchange.com/a/14016/36603
// for more details about how this works.
// TODO Check this again before the Serenity release, because all addresses will be
// contracts then.
// solium-disable-next-line security/no-inline-assembly
assembly { size := extcodesize(addr) }
return size > 0;
}
}
// File: contracts/upgradeability/UpgradeabilityProxy.sol
/**
* @title UpgradeabilityProxy
* @dev This contract implements a proxy that allows to change the
* implementation address to which it will delegate.
* Such a change is called an implementation upgrade.
*/
contract UpgradeabilityProxy is Proxy {
/**
* @dev Emitted when the implementation is upgraded.
* @param implementation Address of the new implementation.
*/
event Upgraded(address indexed implementation);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "org.zeppelinos.proxy.implementation", and is
* validated in the constructor.
*/
bytes32 private constant IMPLEMENTATION_SLOT = 0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3;
/**
* @dev Contract constructor.
* @param _implementation Address of the initial implementation.
* @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
* This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
*/
constructor(address _implementation, bytes _data) public payable {
assert(IMPLEMENTATION_SLOT == keccak256("org.zeppelinos.proxy.implementation"));
_setImplementation(_implementation);
if(_data.length > 0) {
require(_implementation.delegatecall(_data));
}
}
/**
* @dev Returns the current implementation.
* @return Address of the current implementation
*/
function _implementation() internal view returns (address impl) {
bytes32 slot = IMPLEMENTATION_SLOT;
assembly {
impl := sload(slot)
}
}
/**
* @dev Upgrades the proxy to a new implementation.
* @param newImplementation Address of the new implementation.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Sets the implementation address of the proxy.
* @param newImplementation Address of the new implementation.
*/
function _setImplementation(address newImplementation) private {
require(AddressUtils.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address");
bytes32 slot = IMPLEMENTATION_SLOT;
assembly {
sstore(slot, newImplementation)
}
}
}
// File: contracts/upgradeability/AdminUpgradeabilityProxy.sol
/**
* @title AdminUpgradeabilityProxy
* @dev This contract combines an upgradeability proxy with an authorization
* mechanism for administrative tasks.
* All external functions in this contract must be guarded by the
* `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
* feature proposal that would enable this to be done automatically.
*/
contract AdminUpgradeabilityProxy is UpgradeabilityProxy {
/**
* @dev Emitted when the administration has been transferred.
* @param previousAdmin Address of the previous admin.
* @param newAdmin Address of the new admin.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "org.zeppelinos.proxy.admin", and is
* validated in the constructor.
*/
bytes32 private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b;
/**
* @dev Modifier to check whether the `msg.sender` is the admin.
* If it is, it will run the function. Otherwise, it will delegate the call
* to the implementation.
*/
modifier ifAdmin() {
if (msg.sender == _admin()) {
_;
} else {
_fallback();
}
}
/**
* Contract constructor.
* It sets the `msg.sender` as the proxy administrator.
* @param _implementation address of the initial implementation.
* @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
* This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
*/
constructor(address _implementation, bytes _data) UpgradeabilityProxy(_implementation, _data) public payable {
assert(ADMIN_SLOT == keccak256("org.zeppelinos.proxy.admin"));
_setAdmin(msg.sender);
}
/**
* @return The address of the proxy admin.
*/
function admin() external view ifAdmin returns (address) {
return _admin();
}
/**
* @return The address of the implementation.
*/
function implementation() external view ifAdmin returns (address) {
return _implementation();
}
/**
* @dev Changes the admin of the proxy.
* Only the current admin can call this function.
* @param newAdmin Address to transfer proxy administration to.
*/
function changeAdmin(address newAdmin) external ifAdmin {
require(newAdmin != address(0), "Cannot change the admin of a proxy to the zero address");
emit AdminChanged(_admin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev Upgrade the backing implementation of the proxy.
* Only the admin can call this function.
* @param newImplementation Address of the new implementation.
*/
function upgradeTo(address newImplementation) external ifAdmin {
_upgradeTo(newImplementation);
}
/**
* @dev Upgrade the backing implementation of the proxy and call a function
* on the new implementation.
* This is useful to initialize the proxied contract.
* @param newImplementation Address of the new implementation.
* @param data Data to send as msg.data in the low level call.
* It should include the signature and the parameters of the function to be called, as described in
* https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
*/
function upgradeToAndCall(address newImplementation, bytes data) payable external ifAdmin {
_upgradeTo(newImplementation);
require(newImplementation.delegatecall(data));
}
/**
* @return The admin slot.
*/
function _admin() internal view returns (address adm) {
bytes32 slot = ADMIN_SLOT;
assembly {
adm := sload(slot)
}
}
/**
* @dev Sets the address of the proxy admin.
* @param newAdmin Address of the new proxy admin.
*/
function _setAdmin(address newAdmin) internal {
bytes32 slot = ADMIN_SLOT;
assembly {
sstore(slot, newAdmin)
}
}
/**
* @dev Only fall back when the sender is not the admin.
*/
function _willFallback() internal {
require(msg.sender != _admin(), "Cannot call fallback function from the proxy admin");
super._willFallback();
}
}File 2 of 3: Weapons
pragma solidity ^0.4.24;
/**
* @title Initializable
*
* @dev Helper contract to support initializer functions. To use it, replace
* the constructor with a function that has the `initializer` modifier.
* WARNING: Unlike constructors, initializer functions must be manually
* invoked. This applies both to deploying an Initializable contract, as well
* as extending an Initializable contract via inheritance.
* WARNING: When used with inheritance, manual care must be taken to not invoke
* a parent initializer twice, or ensure that all initializers are idempotent,
* because this is not dealt with automatically as with constructors.
*/
contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private initializing;
/**
* @dev Modifier to use in the initializer function of a contract.
*/
modifier initializer() {
require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");
bool wasInitializing = initializing;
initializing = true;
initialized = true;
_;
initializing = wasInitializing;
}
/// @dev Returns true if and only if the function is running in the constructor
function isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
uint256 cs;
assembly { cs := extcodesize(address) }
return cs == 0;
}
// Reserved storage space to allow for layout changes in the future.
uint256[50] private ______gap;
}
/**
* @title IERC165
* @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
*/
interface IERC165 {
/**
* @notice Query if a contract implements an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @dev Interface identification is specified in ERC-165. This function
* uses less than 30,000 gas.
*/
function supportsInterface(bytes4 interfaceId)
external
view
returns (bool);
}
/**
* @title ERC165
* @author Matt Condon (@shrugs)
* @dev Implements ERC165 using a lookup table.
*/
contract ERC165 is IERC165, Initializable {
bytes4 private constant _InterfaceId_ERC165 = 0x01ffc9a7;
/**
* 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)'))
*/
/**
* @dev a mapping of interface id to whether or not it's supported
*/
mapping(bytes4 => bool) internal _supportedInterfaces;
/**
* @dev A contract implementing SupportsInterfaceWithLookup
* implement ERC165 itself
*/
function initialize() initializer public {
_registerInterface(_InterfaceId_ERC165);
}
/**
* @dev implement supportsInterface(bytes4) using a lookup table
*/
function supportsInterface(bytes4 interfaceId)
external
view
returns (bool)
{
return _supportedInterfaces[interfaceId];
}
/**
* @dev private method for registering an interface
*/
function _registerInterface(bytes4 interfaceId)
internal
{
require(interfaceId != 0xffffffff);
_supportedInterfaces[interfaceId] = true;
}
}
// import "./ERC721.sol";
// import "./IERC721.sol";
// import "../../introspection/IERC165.sol";
/**
* @title ERC721 Non-Fungible Token Standard basic interface
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract IERC721 is IERC165 {
event Transfer(
address indexed from,
address indexed to,
uint256 indexed tokenId
);
event Approval(
address indexed owner,
address indexed approved,
uint256 indexed tokenId
);
event ApprovalForAll(
address indexed owner,
address indexed operator,
bool approved
);
function balanceOf(address owner) public view returns (uint256 balance);
function ownerOf(uint256 tokenId) public view returns (address owner);
function approve(address to, uint256 tokenId) public;
function getApproved(uint256 tokenId)
public view returns (address operator);
function setApprovalForAll(address operator, bool _approved) public;
function isApprovedForAll(address owner, address operator)
public view returns (bool);
function transferFrom(address from, address to, uint256 tokenId) public;
function safeTransferFrom(address from, address to, uint256 tokenId)
public;
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes data
)
public;
}
// import "./IERC721Receiver.sol";
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
contract IERC721Receiver {
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a `safeTransfer`. This function MUST return the function selector,
* otherwise the caller will revert the transaction. The selector to be
* returned can be obtained as `this.onERC721Received.selector`. This
* function MAY throw to revert and reject the transfer.
* Note: the ERC721 contract address is always the message sender.
* @param operator The address which called `safeTransferFrom` function
* @param from The address which previously owned the token
* @param tokenId The NFT identifier which is being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes data
)
public
returns(bytes4);
}
// import "../../math/SafeMath.sol";
/**
* @title SafeMath
* @dev Math operations with safety checks that revert on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, reverts on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0);// Solidity only automatically asserts when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b);// There is no case in which this doesn't hold
return c;
}
/**
* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
uint256 c = a - b;
return c;
}
/**
* @dev Adds two numbers, reverts on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}
/**
* @dev Divides two numbers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0);
return a % b;
}
}
// import "../../utils/Address.sol";
/**
* Utility library of inline functions on addresses
*/
library Address {
/**
* Returns whether the target address is a contract
* @dev This function will return false if invoked during the constructor of a contract,
* as the code is not actually created until after the constructor finishes.
* @param account address of the account to check
* @return whether the target address is a contract
*/
function isContract(address account) internal view returns (bool) {
uint256 size;
// XXX Currently there is no better way to check if there is a contract in an address
// than to check the size of the code at that address.
// See https://ethereum.stackexchange.com/a/14016/36603
// for more details about how this works.
// TODO Check this again before the Serenity release, because all addresses will be
// contracts then.
// solium-disable-next-line security/no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
}
/**
* @title ERC721 Non-Fungible Token Standard basic implementation
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721 is ERC165, IERC721 {
using SafeMath for uint256;
using Address for address;
// Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
// which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
// Mapping from token ID to owner
mapping (uint256 => address) private _tokenOwner;
// Mapping from token ID to approved address
mapping (uint256 => address) private _tokenApprovals;
// Mapping from owner to number of owned token
mapping (address => uint256) private _ownedTokensCount;
// Mapping from owner to operator approvals
mapping (address => mapping (address => bool)) private _operatorApprovals;
bytes4 private constant _InterfaceId_ERC721 = 0x80ac58cd;
/*
* 0x80ac58cd ===
* bytes4(keccak256('balanceOf(address)')) ^
* bytes4(keccak256('ownerOf(uint256)')) ^
* bytes4(keccak256('approve(address,uint256)')) ^
* bytes4(keccak256('getApproved(uint256)')) ^
* bytes4(keccak256('setApprovalForAll(address,bool)')) ^
* bytes4(keccak256('isApprovedForAll(address,address)')) ^
* bytes4(keccak256('transferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
*/
function initialize() initializer public {
// register the supported interfaces to conform to ERC721 via ERC165
_registerInterface(_InterfaceId_ERC721);
}
/**
* @dev Gets the balance of the specified address
* @param owner address to query the balance of
* @return uint256 representing the amount owned by the passed address
*/
function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0));
return _ownedTokensCount[owner];
}
/**
* @dev Gets the owner of the specified token ID
* @param tokenId uint256 ID of the token to query the owner of
* @return owner address currently marked as the owner of the given token ID
*/
function ownerOf(uint256 tokenId) public view returns (address) {
address owner = _tokenOwner[tokenId];
require(owner != address(0));
return owner;
}
/**
* @dev Approves another address to transfer the given token ID
* The zero address indicates there is no approved address.
* There can only be one approved address per token at a given time.
* Can only be called by the token owner or an approved operator.
* @param to address to be approved for the given token ID
* @param tokenId uint256 ID of the token to be approved
*/
function approve(address to, uint256 tokenId) public {
address owner = ownerOf(tokenId);
require(to != owner);
require(msg.sender == owner || isApprovedForAll(owner, msg.sender));
_tokenApprovals[tokenId] = to;
emit Approval(owner, to, tokenId);
}
/**
* @dev Gets the approved address for a token ID, or zero if no address set
* Reverts if the token ID does not exist.
* @param tokenId uint256 ID of the token to query the approval of
* @return address currently approved for the given token ID
*/
function getApproved(uint256 tokenId) public view returns (address) {
require(_exists(tokenId));
return _tokenApprovals[tokenId];
}
/**
* @dev Sets or unsets the approval of a given operator
* An operator is allowed to transfer all tokens of the sender on their behalf
* @param to operator address to set the approval
* @param approved representing the status of the approval to be set
*/
function setApprovalForAll(address to, bool approved) public {
require(to != msg.sender);
_operatorApprovals[msg.sender][to] = approved;
emit ApprovalForAll(msg.sender, to, approved);
}
/**
* @dev Tells whether an operator is approved by a given owner
* @param owner owner address which you want to query the approval of
* @param operator operator address which you want to query the approval of
* @return bool whether the given operator is approved by the given owner
*/
function isApprovedForAll(
address owner,
address operator
)
public
view
returns (bool)
{
return _operatorApprovals[owner][operator];
}
/**
* @dev Transfers the ownership of a given token ID to another address
* Usage of this method is discouraged, use `safeTransferFrom` whenever possible
* Requires the msg sender to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
function transferFrom(
address from,
address to,
uint256 tokenId
)
public
{
require(_isApprovedOrOwner(msg.sender, tokenId));
require(to != address(0));
_clearApproval(from, tokenId);
_removeTokenFrom(from, tokenId);
_addTokenTo(to, tokenId);
emit Transfer(from, to, tokenId);
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;otherwise,
* the transfer is reverted.
*
* Requires the msg sender to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
)
public
{
// solium-disable-next-line arg-overflow
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;otherwise,
* the transfer is reverted.
* Requires the msg sender to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes data to send along with a safe transfer check
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes _data
)
public
{
transferFrom(from, to, tokenId);
// solium-disable-next-line arg-overflow
require(_checkAndCallSafeTransfer(from, to, tokenId, _data));
}
/**
* @dev Returns whether the specified token exists
* @param tokenId uint256 ID of the token to query the existence of
* @return whether the token exists
*/
function _exists(uint256 tokenId) internal view returns (bool) {
address owner = _tokenOwner[tokenId];
return owner != address(0);
}
/**
* @dev Returns whether the given spender can transfer a given token ID
* @param spender address of the spender to query
* @param tokenId uint256 ID of the token to be transferred
* @return bool whether the msg.sender is approved for the given token ID,
* is an operator of the owner, or is the owner of the token
*/
function _isApprovedOrOwner(
address spender,
uint256 tokenId
)
internal
view
returns (bool)
{
address owner = ownerOf(tokenId);
// Disable solium check because of
// https://github.com/duaraghav8/Solium/issues/175
// solium-disable-next-line operator-whitespace
return (
spender == owner ||
getApproved(tokenId) == spender ||
isApprovedForAll(owner, spender)
);
}
/**
* @dev Internal function to mint a new token
* Reverts if the given token ID already exists
* @param to The address that will own the minted token
* @param tokenId uint256 ID of the token to be minted by the msg.sender
*/
function _mint(address to, uint256 tokenId) internal {
require(to != address(0));
_addTokenTo(to, tokenId);
emit Transfer(address(0), to, tokenId);
}
/**
* @dev Internal function to burn a specific token
* Reverts if the token does not exist
* @param tokenId uint256 ID of the token being burned by the msg.sender
*/
function _burn(address owner, uint256 tokenId) internal {
_clearApproval(owner, tokenId);
_removeTokenFrom(owner, tokenId);
emit Transfer(owner, address(0), tokenId);
}
/**
* @dev Internal function to clear current approval of a given token ID
* Reverts if the given address is not indeed the owner of the token
* @param owner owner of the token
* @param tokenId uint256 ID of the token to be transferred
*/
function _clearApproval(address owner, uint256 tokenId) internal {
require(ownerOf(tokenId) == owner);
if (_tokenApprovals[tokenId] != address(0)) {
_tokenApprovals[tokenId] = address(0);
}
}
/**
* @dev Internal function to add a token ID to the list of a given address
* @param to address representing the new owner of the given token ID
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function _addTokenTo(address to, uint256 tokenId) internal {
require(_tokenOwner[tokenId] == address(0));
_tokenOwner[tokenId] = to;
_ownedTokensCount[to] = _ownedTokensCount[to].add(1);
}
/**
* @dev Internal function to remove a token ID from the list of a given address
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function _removeTokenFrom(address from, uint256 tokenId) internal {
require(ownerOf(tokenId) == from);
_ownedTokensCount[from] = _ownedTokensCount[from].sub(1);
_tokenOwner[tokenId] = address(0);
}
/**
* @dev Internal function to invoke `onERC721Received` on a target address
* The call is not executed if the target address is not a contract
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return whether the call correctly returned the expected magic value
*/
function _checkAndCallSafeTransfer(
address from,
address to,
uint256 tokenId,
bytes _data
)
internal
returns (bool)
{
if (!to.isContract()) {
return true;
}
bytes4 retval = IERC721Receiver(to).onERC721Received(
msg.sender, from, tokenId, _data);
return (retval == _ERC721_RECEIVED);
}
}
//import "./ERC721Enumerable.sol";
// import "./IERC721Enumerable.sol";
// import "./IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract IERC721Enumerable is IERC721 {
function totalSupply() public view returns (uint256);
function tokenOfOwnerByIndex(
address owner,
uint256 index
)
public
view
returns (uint256 tokenId);
function tokenByIndex(uint256 index) public view returns (uint256);
}
// import "./ERC721.sol";
// import "../../introspection/ERC165.sol";
contract ERC721Enumerable is ERC165, ERC721, IERC721Enumerable {
// Mapping from owner to list of owned token IDs
mapping(address => uint256[]) private _ownedTokens;
// Mapping from token ID to index of the owner tokens list
mapping(uint256 => uint256) private _ownedTokensIndex;
// Array with all token ids, used for enumeration
uint256[] private _allTokens;
// Mapping from token id to position in the allTokens array
mapping(uint256 => uint256) private _allTokensIndex;
bytes4 private constant _InterfaceId_ERC721Enumerable = 0x780e9d63;
/**
* 0x780e9d63 ===
* bytes4(keccak256('totalSupply()')) ^
* bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^
* bytes4(keccak256('tokenByIndex(uint256)'))
*/
/**
* @dev Constructor function
*/
function initialize() initializer public {
// register the supported interface to conform to ERC721 via ERC165
_registerInterface(_InterfaceId_ERC721Enumerable);
}
/**
* @dev Gets the token ID at a given index of the tokens list of the requested owner
* @param owner address owning the tokens list to be accessed
* @param index uint256 representing the index to be accessed of the requested tokens list
* @return uint256 token ID at the given index of the tokens list owned by the requested address
*/
function tokenOfOwnerByIndex(
address owner,
uint256 index
)
public
view
returns (uint256)
{
require(index < balanceOf(owner));
return _ownedTokens[owner][index];
}
/**
* @dev Gets the total amount of tokens stored by the contract
* @return uint256 representing the total amount of tokens
*/
function totalSupply() public view returns (uint256) {
return _allTokens.length;
}
/**
* @dev Gets the token ID at a given index of all the tokens in this contract
* Reverts if the index is greater or equal to the total number of tokens
* @param index uint256 representing the index to be accessed of the tokens list
* @return uint256 token ID at the given index of the tokens list
*/
function tokenByIndex(uint256 index) public view returns (uint256) {
require(index < totalSupply());
return _allTokens[index];
}
/**
* @dev Internal function to add a token ID to the list of a given address
* @param to address representing the new owner of the given token ID
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function _addTokenTo(address to, uint256 tokenId) internal {
super._addTokenTo(to, tokenId);
uint256 length = _ownedTokens[to].length;
_ownedTokens[to].push(tokenId);
_ownedTokensIndex[tokenId] = length;
}
/**
* @dev Internal function to remove a token ID from the list of a given address
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function _removeTokenFrom(address from, uint256 tokenId) internal {
super._removeTokenFrom(from, tokenId);
// To prevent a gap in the array, we store the last token in the index of the token to delete, and
// then delete the last slot.
uint256 tokenIndex = _ownedTokensIndex[tokenId];
uint256 lastTokenIndex = _ownedTokens[from].length.sub(1);
uint256 lastToken = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastToken;
// This also deletes the contents at the last position of the array
_ownedTokens[from].length--;
// Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
// be zero. Then we can make sure that we will remove tokenId from the ownedTokens list since we are first swapping
// the lastToken to the first position, and then dropping the element placed in the last position of the list
_ownedTokensIndex[tokenId] = 0;
_ownedTokensIndex[lastToken] = tokenIndex;
}
/**
* @dev Internal function to mint a new token
* Reverts if the given token ID already exists
* @param to address the beneficiary that will own the minted token
* @param tokenId uint256 ID of the token to be minted by the msg.sender
*/
function _mint(address to, uint256 tokenId) internal {
super._mint(to, tokenId);
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
/**
* @dev Internal function to burn a specific token
* Reverts if the token does not exist
* @param owner owner of the token to burn
* @param tokenId uint256 ID of the token being burned by the msg.sender
*/
function _burn(address owner, uint256 tokenId) internal {
super._burn(owner, tokenId);
// Reorg all tokens array
uint256 tokenIndex = _allTokensIndex[tokenId];
uint256 lastTokenIndex = _allTokens.length.sub(1);
uint256 lastToken = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastToken;
_allTokens[lastTokenIndex] = 0;
_allTokens.length--;
_allTokensIndex[tokenId] = 0;
_allTokensIndex[lastToken] = tokenIndex;
}
}
// import "./ERC721Metadata.sol";
// import "./IERC721Metadata.sol";
// import "./IERC721.sol";
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable is Initializable {
address private _owner;
event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function initialize(address addr) initializer public {
// can not be same as deployer!
_owner = addr;
}
/**
* @return the address of the owner.
*/
function owner() public view returns(address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier contract_onlyOwner() {
require(isOwner());
_;
}
/**
* @return true if `msg.sender` is the owner of the contract.
*/
function isOwner() public view returns(bool) {
return msg.sender == _owner;
}
/**
* @dev Allows the current owner to relinquish control of the contract.
* @notice Renouncing to ownership will leave the contract without an owner.
* It will not be possible to call the functions with the `onlyOwner`
* modifier anymore.
*/
function renounceOwnership() public contract_onlyOwner {
emit OwnershipRenounced(_owner);
_owner = address(0);
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public contract_onlyOwner {
_transferOwnership(newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0));
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
/**
* @title Helper to allow various addresses to mint Chibis
* @dev Adds addresses to mapping that can be true/false queried
*/
contract MintWallets is Ownable {
mapping (address => bool) internal _mintWallets;
function initialize(address addr) initializer public {
_mintWallets[msg.sender] = true;
_mintWallets[addr] = true;
}
/**
* @dev Add a wallet/contract to the mint function functionality
* @param _address The address/contract to allow minting
*/
function setMintAddress(address _address, bool _active) public contract_onlyOwner {
_mintWallets[_address] = _active;
}
/**
* @dev Check if wallet is true/false
* @param _address The address/contract to check
*/
function checkMintAllowed(address _address) public view returns (bool) {
return _mintWallets[_address];
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier mintAllowed(address _address) {
require(_mintWallets[_address]);
_;
}
}
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract IERC721Metadata is IERC721 {
function name() external view returns (string);
function symbol() external view returns (string);
function tokenURI(uint256 tokenId) public view returns (string);
}
// import "../../introspection/ERC165.sol";
contract ERC721Metadata is ERC165, ERC721, IERC721Metadata, MintWallets {
// Token name
string internal _name;
// Token symbol
string internal _symbol;
string infoUrlPrefix;
bytes4 private constant InterfaceId_ERC721Metadata = 0x5b5e139f;
/**
* 0x5b5e139f ===
* bytes4(keccak256('name()')) ^
* bytes4(keccak256('symbol()')) ^
* bytes4(keccak256('tokenURI(uint256)'))
*/
/**
* @dev Constructor function
*/
function initialize(string name, string symbol) initializer public {
_name = name;
_symbol = symbol;
// register the supported interfaces to conform to ERC721 via ERC165
_registerInterface(InterfaceId_ERC721Metadata);
}
/**
* @dev Gets the token name
* @return string representing the token name
*/
function name() external view returns (string) {
return _name;
}
/**
* @dev Gets the token symbol
* @return string representing the token symbol
*/
function symbol() external view returns (string) {
return _symbol;
}
/**
* @dev Returns an URI for a given token ID
* Throws if the token ID does not exist. May return an empty string.
* @param tokenId uint256 ID of the token to query
*/
function tokenURI(uint256 tokenId) public view returns (string) {
require(_exists(tokenId));
string memory uri = strConcat(infoUrlPrefix, uint2str(tokenId));
return uri;
}
/**
* @dev Internal function to burn a specific token
* Reverts if the token does not exist
* @param owner owner of the token to burn
* @param tokenId uint256 ID of the token being burned by the msg.sender
*/
function _burn(address owner, uint256 tokenId) internal {
super._burn(owner, tokenId);
}
// set info url for weapons
function setInfoUrl(string _url) public contract_onlyOwner returns(bool success) {
infoUrlPrefix = _url;
return true;
}
/**
*
* Helper stuff
*
**/
function stringToBytes32(string memory source) internal pure returns (bytes32 result) {
bytes memory tempEmptyStringTest = bytes(source);
if (tempEmptyStringTest.length == 0) {
return 0x0;
}
assembly {
result := mload(add(source, 32))
}
}
function strConcat(string _a, string _b) internal pure returns (string) {
return strConcatDoIt(_a, _b, "", "", "");
}
function strConcatDoIt(string _a, string _b, string _c, string _d, string _e) internal pure returns (string) {
bytes memory _ba = bytes(_a);
bytes memory _bb = bytes(_b);
bytes memory _bc = bytes(_c);
bytes memory _bd = bytes(_d);
bytes memory _be = bytes(_e);
string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
bytes memory babcde = bytes(abcde);
uint k = 0;
for (uint i = 0;i < _ba.length;i++) babcde[k++] = _ba[i];
for (i = 0;i < _bb.length;i++) babcde[k++] = _bb[i];
for (i = 0;i < _bc.length;i++) babcde[k++] = _bc[i];
for (i = 0;i < _bd.length;i++) babcde[k++] = _bd[i];
for (i = 0;i < _be.length;i++) babcde[k++] = _be[i];
return string(babcde);
}
function uint2str(uint i) internal pure returns (string){
if (i == 0) return "0";
uint j = i;
uint len;
while (j != 0){
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (i != 0){
bstr[k--] = byte(48 + i % 10);
i /= 10;
}
return string(bstr);
}
function bytesToUint(bytes b) internal pure returns (uint256) {
require(b.length == 32);
bytes32 out;
for (uint i = 0;i < 32;i++) {
out |= bytes32(b[i] & 0xFF) >> (i * 8);
}
return uint256(out);
}
}
/**
* @title Full ERC721 Token
* This implementation includes all the required and some optional functionality of the ERC721 standard
* Moreover, it includes approve all functionality using operator terminology
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721Full is ERC721, ERC721Enumerable, ERC721Metadata {
string name;
string symbol;
function initialize() initializer public {
name = 'weapons';
symbol = 'CBW';
ERC721Metadata.initialize(name, symbol);
}
}
interface ERC20InterfaceClassic {
function transfer(address to, uint tokens) external returns (bool success);
}
interface ERC20Interface {
function transferFrom(address from, address to, uint tokens) external returns (bool success);
function transfer(address to, uint tokens) external;
function balanceOf(address _owner) external view returns (uint256 _balance);
}
contract Referral is Ownable {
uint refIdCounter;
uint refCutPerc;
mapping (address => uint) refId;
mapping (uint => address) refIdAddress;
mapping (uint => uint) refCut;
mapping (uint => uint) refIdAvail;
event RefPaid(uint refId, address indexed refOwner, uint amount);
event RefCreated(uint refId, address indexed wallet);
function initialize() initializer public {
refIdCounter = 400;
refCutPerc = 12;
}
// creates a new refid if address has none
function createRefId() public {
require(refId[msg.sender] == 0);
refIdCounter++;
refId[msg.sender] = refIdCounter;
refIdAddress[refIdCounter] = msg.sender;
refCut[refIdCounter] = refCutPerc;
emit RefCreated(refIdCounter, msg.sender);
}
function setRefCut(uint _refId, uint _cut) public contract_onlyOwner {
refCut[_refId] = _cut;
}
// user can query his own ref data, not that of others
function queryRefId() public view returns(uint _refId, uint _refCut, address _address) {
uint _id = refId[msg.sender];
return (_id, refCut[_id], refIdAddress[_id]);
}
}
contract WeaponGenesInterface {
function generateData(uint _tokenId) public view returns (uint, uint);
function generateRareMythicData(uint _tokenId) public view returns (uint);
function generateLegendaryData(uint _tokenId) public view returns (uint);
}
// new and old chibi contract
contract ChibiInterface {
function queryChibiDNA(uint) public pure returns (
uint16[13]
) {}
function ownerOf(uint256) public pure returns (address) {}
// legacy support old chibi contract
function queryChibi(uint) public pure returns (
string,
string,
uint16[13],
uint256,
uint256,
uint,
uint
) {}
}
/**
* Weapons for Chibis
*
*/
contract Weapons is ERC721Full, Referral {
// couple events
event WeaponClaimed(address indexed from, uint chibiId, uint weaponTokenId, uint weaponRarity, uint weaponType);
event WeaponSaleBought(address indexed from, address indexed to, uint weaponTokenId, uint weaponPricePlayer, uint weaponPrice);
event WeaponBought(address indexed from, uint weaponTokenId, uint weaponRarity, uint weaponType);
event WeaponMintedToAddr(address indexed from, uint weaponTokenId, uint weaponRarity, uint weaponType, string weaponCode);
event WeaponForSale(address indexed from, uint weaponTokenId, uint weaponPrice);
event WeaponSaleCancelled(address indexed from, uint weaponTokenId);
uint uniqueCounter;
ChibiInterface chibiContract;
WeaponGenesInterface genesContract;
// default weapon price
uint _weaponPrice;
uint _rareWeaponPrice;
uint _mythicWeaponPrice;
uint _legendaryWeaponPrice;
// sell weapon internally
mapping(uint256 => uint256) private _weaponSalePrice;
// mapping for Chibi to claim weapon
mapping(uint256 => bool) private _weaponClaimed;
// our comission
uint comission;
// for players putting weapons up, to avoid super low prices from botters
uint minPrice;
struct WeaponsData {
uint rarity;
uint weaponType;
}
bool public gameState;
bool public gameStateClaim;
mapping(uint256 => WeaponsData) private weapons;
uint presaleLockdown;
function initialize() initializer public {
// 2019-02-28 00:00:00
presaleLockdown = 1551312000;
ERC721Full.initialize();
ERC165.initialize();
ERC721.initialize();
ERC721Enumerable.initialize();
Ownable.initialize(address(0x3e0f98ea1B916BB2373BAf21c2C8E6eE970e1126));
MintWallets.initialize(address(0x3e0f98ea1B916BB2373BAf21c2C8E6eE970e1126));
Referral.initialize();
// min price people can put up weapons
minPrice = 100;
// prices based on droprates
_weaponPrice = 20000000000000000; // 0.02 ETH ~3.50 USD (nov 18)
_rareWeaponPrice = 88000000000000000; // 0.088 ETH
_mythicWeaponPrice = 200000000000000000; // 0.2 ETH
_legendaryWeaponPrice = 3000000000000000000; // 3 ETH
uniqueCounter = 0;
infoUrlPrefix = "https://chibifighters.io/weaponapi/";
// set comission percentage inv
comission = 90;
gameState = true;
gameStateClaim = true;
}
// returns min price for weapon sale to avoid cheap sales
function queryMinPrice() public view returns (uint price) {
return minPrice;
}
function queryDefaultSalePrice(uint rarity) public view returns (uint price) {
if (rarity == 0) {
return _weaponPrice;
}else
if (rarity == 1) {
return _rareWeaponPrice;
}else
if (rarity == 2) {
return _mythicWeaponPrice;
}else
if (rarity == 3) {
return _legendaryWeaponPrice;
}
return 0;
}
// returns min price for weapon sale to avoid cheap sales
function setMinPrice(uint _minPrice) public contract_onlyOwner returns (uint price) {
minPrice = _minPrice;
return minPrice;
}
// returns min price for weapon sale to avoid cheap sales
function setGameState(bool _paused) public contract_onlyOwner returns (bool paused) {
gameState = _paused;
return gameState;
}
// returns min price for weapon sale to avoid cheap sales
function setGameStateClaim(bool _paused) public contract_onlyOwner returns (bool paused) {
gameStateClaim = _paused;
return gameState;
}
function queryWeaponData(uint _tokenId) public view returns (uint tokenId, address owner, uint rarity, uint weaponType) {
return (
_tokenId,
ownerOf(_tokenId),
weapons[_tokenId].rarity,
weapons[_tokenId].weaponType
);
}
// check if chibi already claimed weapon
function queryChibiClaimed(uint chibiId) public view returns (bool success) {
return _weaponClaimed[chibiId];
}
function setCommission(uint percent) public contract_onlyOwner returns(bool success) {
comission = 100 - percent;
return true;
}
function getCommission() public view contract_onlyOwner returns(uint _comission) {
return 100 - comission;
}
function putWeaponForSale(uint tokenId, uint price) public notPaused returns (bool success) {
require (msg.sender == ownerOf(tokenId));
require (price >= minPrice);
_weaponSalePrice[tokenId] = price;
approve(this, tokenId);
emit WeaponForSale(msg.sender, tokenId, price);
return true;
}
function cancelWeaponSale(uint tokenId) public returns (bool success) {
require (msg.sender == ownerOf(tokenId));
_weaponSalePrice[tokenId] = 0;
// remove approval from contract
_clearApproval(msg.sender, tokenId);
emit WeaponSaleCancelled(msg.sender, tokenId);
return true;
}
function buySaleWeapon(uint tokenId) public payable notPaused returns (bool success) {
require(msg.sender != ownerOf(tokenId));
require(_weaponSalePrice[tokenId] > 0);
require(msg.value == _weaponSalePrice[tokenId]);
require(_isApprovedOrOwner(this, tokenId));
address _to = msg.sender;
require(_to != address(0));
_weaponSalePrice[tokenId] = 0;
address _from = ownerOf(tokenId);
uint finalPrice = msg.value / 100 * comission;
// transfer weapon
_removeTokenFrom(_from, tokenId);
_addTokenTo(_to, tokenId);
_clearApproval(msg.sender, tokenId);
emit Transfer(_from, _to, tokenId);
// transfer ether
_from.transfer(finalPrice);
emit WeaponSaleBought(_from, _to, tokenId, finalPrice, msg.value);
return true;
}
// price for default weapons
function setWeaponPrice(uint mode, uint _setWeaponPrice) public contract_onlyOwner returns(bool success, uint weaponPrice) {
if (mode == 0) {
_weaponPrice = _setWeaponPrice;
}else
if (mode == 1) {
_rareWeaponPrice = _setWeaponPrice;
}else
if (mode == 2) {
_mythicWeaponPrice = _setWeaponPrice;
}else
if (mode == 3) {
_legendaryWeaponPrice = _setWeaponPrice;
}
return (true, _setWeaponPrice);
}
// set chibi contract
function setChibiAddress(address _address) public contract_onlyOwner returns (bool success) {
chibiContract = ChibiInterface(_address);
return true;
}
// set genes contract
function setGenesAddress(address _address) public contract_onlyOwner returns (bool success) {
genesContract = WeaponGenesInterface(_address);
return true;
}
// get dna to claim weapons (only way to get founder weapons)
function getChibiWeaponDna(uint _chibiId) internal view returns (uint weapon, uint rarity) {
uint16[13] memory _dna = chibiContract.queryChibiDNA(_chibiId);
return (_dna[7], _dna[8]);
}
// buy a random weapon, can be anything from common to legendary
function buyWeapon(uint amount, uint _refId) public payable notPaused {
require(_weaponPrice.mul(amount) == msg.value);
// founder weapons can not be bought, and nothing that doesn't exist yet
for (uint i=0;i<amount;i++) {
uniqueCounter++;
require(!_exists(uniqueCounter));
// mint also triggers transfer event
_mint(address(msg.sender), uniqueCounter);
(uint _weaponRarity, uint _weaponType) = genesContract.generateData(uniqueCounter);
weapons[uniqueCounter].rarity = _weaponRarity;
weapons[uniqueCounter].weaponType = _weaponType;
emit WeaponBought(msg.sender, uniqueCounter, _weaponRarity, _weaponType);
}
if (refIdAddress[_refId] != address(0) && msg.sender != refIdAddress[_refId]) {
uint amountRef = msg.value.mul(refCut[_refId]).div(100);
refIdAddress[_refId].transfer(amountRef);
emit RefPaid(_refId, refIdAddress[_refId], amountRef);
}
}
// buy a guaranteed rare weapon
function buyWeaponRare(uint amount, uint _refId) public payable notPaused {
require(_rareWeaponPrice.mul(amount) == msg.value);
require(now < presaleLockdown);
for (uint i=0;i<amount;i++) {
uniqueCounter++;
require(!_exists(uniqueCounter));
// mint also triggers transfer event
_mint(address(msg.sender), uniqueCounter);
uint _weaponType = genesContract.generateRareMythicData(uniqueCounter);
weapons[uniqueCounter].rarity = 1;
weapons[uniqueCounter].weaponType = _weaponType;
emit WeaponBought(msg.sender, uniqueCounter, 1, _weaponType);
}
if (refIdAddress[_refId] != address(0) && msg.sender != refIdAddress[_refId]) {
uint amountRef = msg.value.mul(refCut[_refId]).div(100);
refIdAddress[_refId].transfer(amountRef);
emit RefPaid(_refId, refIdAddress[_refId], amountRef);
}
}
// buy a guaranteed mythic weapon
function buyWeaponMythic(uint amount, uint _refId) public payable notPaused {
require(_mythicWeaponPrice.mul(amount) == msg.value);
require(now < presaleLockdown);
for (uint i=0;i<amount;i++) {
uniqueCounter++;
require(!_exists(uniqueCounter));
// mint also triggers transfer event
_mint(address(msg.sender), uniqueCounter);
uint _weaponType = genesContract.generateRareMythicData(uniqueCounter);
weapons[uniqueCounter].rarity = 2;
weapons[uniqueCounter].weaponType = _weaponType;
emit WeaponBought(msg.sender, uniqueCounter, 2, _weaponType);
}
if (refIdAddress[_refId] != address(0) && msg.sender != refIdAddress[_refId]) {
uint amountRef = msg.value.mul(refCut[_refId]).div(100);
refIdAddress[_refId].transfer(amountRef);
emit RefPaid(_refId, refIdAddress[_refId], amountRef);
}
}
// buy a guaranteed legendary weapon
function buyWeaponLegendary(uint amount, uint _refId) public payable notPaused {
require(_legendaryWeaponPrice.mul(amount) == msg.value);
require(now < presaleLockdown);
for (uint i=0;i<amount;i++) {
uniqueCounter++;
require(!_exists(uniqueCounter));
// mint also triggers transfer event
_mint(address(msg.sender), uniqueCounter);
uint _weaponType = genesContract.generateLegendaryData(uniqueCounter);
weapons[uniqueCounter].rarity = 3;
weapons[uniqueCounter].weaponType = _weaponType;
emit WeaponBought(msg.sender, uniqueCounter, 3, _weaponType);
}
if (refIdAddress[_refId] != address(0) && msg.sender != refIdAddress[_refId]) {
uint amountRef = msg.value.mul(refCut[_refId]).div(100);
refIdAddress[_refId].transfer(amountRef);
emit RefPaid(_refId, refIdAddress[_refId], amountRef);
}
}
// mint weapon as result of voucher purchase or what not
// code is used to identify weapon and apply required stats
function mintWeaponToAddr(uint _weaponRarity, uint _weaponType, address _receiver, string _code) public mintAllowed(msg.sender) {
if (_weaponType < 10 || (_weaponType>=8000 && _weaponType<=8013)) revert();
uniqueCounter++;
require(!_exists(uniqueCounter));
// mint also triggers transfer event
_mint(address(_receiver), uniqueCounter);
weapons[uniqueCounter].rarity = _weaponRarity;
weapons[uniqueCounter].weaponType = _weaponType;
emit WeaponMintedToAddr(_receiver, uniqueCounter, _weaponRarity, _weaponType, _code);
}
// Chibis can claim their initial weapon
// that is also the only way to get a founder weapon
//
function claimWeapon(uint _chibiId) public claimNotPaused {
require(chibiContract.ownerOf(_chibiId) == msg.sender);
require(_weaponClaimed[_chibiId] == false);
uniqueCounter++;
// mark claimed
_weaponClaimed[_chibiId] = true;
// get weapon dna of chibi
(uint _weaponType, uint _chibiRarity) = getChibiWeaponDna(_chibiId);
_mint(address(msg.sender), uniqueCounter);
weapons[uniqueCounter].weaponType = _weaponType;
if (_weaponType < 10 || _weaponType > 7999) {
weapons[uniqueCounter].rarity = 3;
} else {
// rarity comes from chibi when claimed, however legendary chibis still get just a mythic weapon since legendary weapons are either bought or made with a fragment
if (_chibiRarity == 3) weapons[uniqueCounter].rarity = 2;
else weapons[uniqueCounter].rarity = _chibiRarity;
}
emit WeaponClaimed(msg.sender, _chibiId, uniqueCounter, weapons[uniqueCounter].rarity, weapons[uniqueCounter].weaponType);
}
// old chibi contract
function claimWeaponOld(uint _chibiId) public notPaused {
require(chibiContract.ownerOf(_chibiId) == msg.sender);
require(_weaponClaimed[_chibiId] == false);
uniqueCounter++;
// mark claimed
_weaponClaimed[_chibiId] = true;
// get weapon dna of chibi
uint16[13] memory _dna;
(
,
,
_dna,
,
,
,
) = chibiContract.queryChibi(_chibiId);
uint _weaponType = _dna[7];
uint _chibiRarity = _dna[8];
_mint(address(msg.sender), uniqueCounter);
weapons[uniqueCounter].weaponType = _weaponType;
if (_weaponType < 10 || _weaponType > 7999) {
weapons[uniqueCounter].rarity = 3;
}else {
// rarity comes from chibi when claimed, however legendary chibis still get just a mythic weapon since legendary weapons are either bought or made with a fragment
if (_chibiRarity == 3) weapons[uniqueCounter].rarity = 2;
else weapons[uniqueCounter].rarity = _chibiRarity;
}
emit WeaponClaimed(msg.sender, _chibiId, uniqueCounter, weapons[uniqueCounter].rarity, weapons[uniqueCounter].weaponType);
}
function queryForSale(uint _tokenId) public view returns (uint price, address owner) {
require(_isApprovedOrOwner(this, _tokenId));
return (
_weaponSalePrice[_tokenId],
ownerOf(_tokenId)
);
}
/**
* @dev Send Ether to owner
* @param _address Receiving address
* @param _amountWei Amount in WEI to send
**/
function weiToOwner(address _address, uint _amountWei) public contract_onlyOwner returns (bool success) {
require(_amountWei <= address(this).balance);
_address.transfer(_amountWei);
return true;
}
function ERC20ToOwner(address _to, uint256 _amount, ERC20Interface _tokenContract) public contract_onlyOwner {
_tokenContract.transfer(_to, _amount);
}
function ERC20ClassicToOwner(address _to, uint256 _amount, ERC20InterfaceClassic _tokenContract) public contract_onlyOwner {
_tokenContract.transfer(_to, _amount);
}
function queryERC20(ERC20Interface _tokenContract) public view contract_onlyOwner returns (uint) {
return _tokenContract.balanceOf(this);
}
modifier notPaused() {
require(gameState == false);
_;
}
modifier claimNotPaused() {
require(gameStateClaim == false);
_;
}
}File 3 of 3: ChibiFighters
pragma solidity ^0.4.21;
// ----------------------------------------------------------------------------
// Contract owner and transfer functions
// just in case someone wants to get my bacon
// ----------------------------------------------------------------------------
contract ContractOwned {
address public contract_owner;
address public contract_newOwner;
event OwnershipTransferred(address indexed _from, address indexed _to);
constructor() public {
contract_owner = msg.sender;
}
modifier contract_onlyOwner {
require(msg.sender == contract_owner);
_;
}
function transferOwnership(address _newOwner) public contract_onlyOwner {
contract_newOwner = _newOwner;
}
function acceptOwnership() public {
require(msg.sender == contract_newOwner);
emit OwnershipTransferred(contract_owner, contract_newOwner);
contract_owner = contract_newOwner;
contract_newOwner = address(0);
}
}
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Substracts two numbers, returns 0 if it would go into minus range.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
if (b >= a) {
return 0;
}
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
/**
* ERC721 compatibility from
* https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/token/ERC721/ERC721Token.sol
* plus our magic sauce
*/
/**
* @title Custom CustomEvents
* @dev some custom events specific to this contract
*/
contract CustomEvents {
event ChibiCreated(uint tokenId, address indexed _owner, bool founder, string _name, uint16[13] dna, uint father, uint mother, uint gen, uint adult, string infoUrl);
event ChibiForFusion(uint tokenId, uint price);
event ChibiForFusionCancelled(uint tokenId);
event WarriorCreated(uint tokenId, string battleRoar);
}
/**
* @title ERC721 interface
* @dev see https://github.com/ethereum/eips/issues/721
*/
contract ERC721 {
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
function balanceOf(address _owner) public view returns (uint256 _balance);
function ownerOf(uint256 _tokenId) public view returns (address _owner);
function transfer(address _to, uint256 _tokenId) public;
function approve(address _to, uint256 _tokenId) public;
function takeOwnership(uint256 _tokenId) public;
function tokenMetadata(uint256 _tokenId) constant public returns (string infoUrl);
function tokenURI(uint256 _tokenId) public view returns (string);
}
// interacting with gene contract
contract GeneInterface {
// creates genes when bought directly on this contract, they will always be superb
// address, seed, founder, tokenId
function createGenes(address, uint, bool, uint, uint) external view returns (
uint16[13] genes
);
// transfusion chamber, no one really knows what that crazy thing does
// except the scientists, but they giggle all day long
// address, seed, tokenId
function splitGenes(address, uint, uint) external view returns (
uint16[13] genes
);
function exhaustAfterFusion(uint _gen, uint _counter, uint _exhaustionTime) public pure returns (uint);
function exhaustAfterBattle(uint _gen, uint _exhaust) public pure returns (uint);
}
// interacting with fcf contract
contract FcfInterface {
function balanceOf(address) public pure returns (uint) {}
function transferFrom(address, address, uint) public pure returns (bool) {}
}
// interacting with battle contract
contract BattleInterface {
function addWarrior(address, uint, uint8, string) pure public returns (bool) {}
function isDead(uint) public pure returns (bool) {}
}
/**
* @title ERC721Token
* Generic implementation for the required functionality of the ERC721 standard
*/
contract ChibiFighters is ERC721, ContractOwned, CustomEvents {
using SafeMath for uint256;
// Total amount of tokens
uint256 private totalTokens;
// Mapping from token ID to owner
mapping (uint256 => address) private tokenOwner;
// Mapping from token ID to approved address
mapping (uint256 => address) private tokenApprovals;
// Mapping from owner to list of owned token IDs
mapping (address => uint256[]) private ownedTokens;
// Mapping from token ID to index of the owner tokens list
mapping(uint256 => uint256) private ownedTokensIndex;
// interfaces for other contracts, so updates are possible
GeneInterface geneContract;
FcfInterface fcfContract;
BattleInterface battleContract;
address battleContractAddress;
// default price for 1 Chibi
uint public priceChibi;
// minimum price for fusion chibis
uint priceFusionChibi;
// counter that keeps upping with each token
uint uniqueCounter;
// time to become adult
uint adultTime;
// recovery time after each fusion
uint exhaustionTime;
// our comission
uint comission;
// battleRemoveContractAddress to remove from array
address battleRemoveContractAddress;
struct Chibi {
// address of current chibi owner
address owner;
// belongs to og
bool founder;
// name of the chibi, chibis need names
string nameChibi;
// the dna, specifies, bodyparts, etc.
// array is easier to decode, but we are not reinventing the wheel here
uint16[13] dna;
// originates from tokenIds, gen0s will return 0
// uint size only matters in structs
uint256 father;
uint256 mother;
// generations, gen0 is created from the incubator, they are pure
// but of course the funniest combos will come from the fusion chamber
uint gen;
// fusions, the beautiful fusion Chibis that came out of this one
uint256[] fusions;
// up for fusion?
bool forFusion;
// cost to fusion with this Chibi, can be set by player at will
uint256 fusionPrice;
// exhaustion after fusion
uint256 exhausted;
// block after which chibi is an adult
uint256 adult;
// info url
string infoUrl;
}
// the link to chibis website
string _infoUrlPrefix;
Chibi[] public chibies;
string public constant name = "Chibi Fighters";
string public constant symbol = "CBF";
// pause function so fusion and minting can be paused for updates
bool paused;
bool fcfPaused;
bool fusionPaused; // needed so founder can fuse while game is paused
/**
* @dev Run only once at contract creation
*/
constructor() public {
// a helping counter to keep chibis unique
uniqueCounter = 0;
// inital price in wei
priceChibi = 100000000000000000;
// default price to allow fusion
priceFusionChibi = 10000000000000000;
// time to become adult
adultTime = 2 hours;
//exhaustionTime = 3 hours;
exhaustionTime = 1 hours;
// start the contract paused
paused = true;
fcfPaused = true;
fusionPaused = true;
// set comission percentage 100-90 = 10%
comission = 90;
_infoUrlPrefix = "https://chibigame.io/chibis.php?idj=";
}
/**
* @dev Set Comission rate 100-x = %
* @param _comission Rate inverted
*/
function setComission(uint _comission) public contract_onlyOwner returns(bool success) {
comission = _comission;
return true;
}
/**
* @dev Set minimum price for fusion Chibis in Wei
*/
function setMinimumPriceFusion(uint _price) public contract_onlyOwner returns(bool success) {
priceFusionChibi = _price;
return true;
}
/**
* @dev Set time until Chibi is considered adult
* @param _adultTimeSecs Set time in seconds
*/
function setAdultTime(uint _adultTimeSecs) public contract_onlyOwner returns(bool success) {
adultTime = _adultTimeSecs;
return true;
}
/**
* @dev Fusion Chamber Cool down
* @param _exhaustionTime Set time in seconds
*/
function setExhaustionTime(uint _exhaustionTime) public contract_onlyOwner returns(bool success) {
exhaustionTime = _exhaustionTime;
return true;
}
/**
* @dev Set game state paused for updates, pauses the entire creation
* @param _setPaused Boolean sets the game paused or not
*/
function setGameState(bool _setPaused) public contract_onlyOwner returns(bool _paused) {
paused = _setPaused;
fcfPaused = _setPaused;
fusionPaused = _setPaused;
return paused;
}
/**
* @dev Set game state for fcf tokens only, so Founder can get Chibis pre launch
* @param _setPaused Boolean sets the game paused or not
*/
function setGameStateFCF(bool _setPaused) public contract_onlyOwner returns(bool _pausedFCF) {
fcfPaused = _setPaused;
return fcfPaused;
}
/**
* @dev unpause Fusions so Founder can Fuse
* @param _setPaused Boolean sets the game paused or not
*/
function setGameStateFusion(bool _setPaused) public contract_onlyOwner returns(bool _pausedFusions) {
fusionPaused = _setPaused;
return fusionPaused;
}
/**
* @dev Query game state. Paused (True) or not?
*/
function getGameState() public constant returns(bool _paused) {
return paused;
}
/**
* @dev Set url prefix
*/
function setInfoUrlPrefix(string prefix) external contract_onlyOwner returns (string infoUrlPrefix) {
_infoUrlPrefix = prefix;
return _infoUrlPrefix;
}
/**
* @dev Set infoUrl of chibi
*/
function changeInfoUrl(uint _tokenId, string _infoUrl) public returns (bool success) {
if (ownerOf(_tokenId) != msg.sender && msg.sender != contract_owner) revert();
chibies[_tokenId].infoUrl = _infoUrl;
return true;
}
/**
* @dev Connect to Founder contract so user can pay in FCF
*/
function setFcfContractAddress(address _address) external contract_onlyOwner returns (bool success) {
fcfContract = FcfInterface(_address);
return true;
}
/**
* @dev Connect to Battle contract
*/
function setBattleContractAddress(address _address) external contract_onlyOwner returns (bool success) {
battleContract = BattleInterface(_address);
battleContractAddress = _address;
return true;
}
/**
* @dev Connect to Battle contract
*/
function setBattleRemoveContractAddress(address _address) external contract_onlyOwner returns (bool success) {
battleRemoveContractAddress = _address;
return true;
}
/**
* @dev Rename a Chibi
* @param _tokenId ID of the Chibi
* @param _name Name of the Chibi
*/
function renameChibi(uint _tokenId, string _name) public returns (bool success){
require(ownerOf(_tokenId) == msg.sender);
chibies[_tokenId].nameChibi = _name;
return true;
}
/**
* @dev Has chibi necromancer trait?
* @param _tokenId ID of the chibi
*/
function isNecromancer(uint _tokenId) public view returns (bool) {
for (uint i=10; i<13; i++) {
if (chibies[_tokenId].dna[i] == 1000) {
return true;
}
}
return false;
}
/**
* @dev buy Chibis with Founders
*/
function buyChibiWithFcf(string _name, string _battleRoar, uint8 _region, uint _seed) public returns (bool success) {
// must own at least 1 FCF, only entire FCF can be swapped for Chibis
require(fcfContract.balanceOf(msg.sender) >= 1 * 10 ** 18);
require(fcfPaused == false);
// prevent hack
uint fcfBefore = fcfContract.balanceOf(address(this));
// user must approved Founders contract to take tokens from account
// oh my, this will need a tutorial video
// always only take 1 Founder at a time
if (fcfContract.transferFrom(msg.sender, this, 1 * 10 ** 18)) {
_mint(_name, _battleRoar, _region, _seed, true, 0);
}
// prevent hacking
assert(fcfBefore == fcfContract.balanceOf(address(this)) - 1 * 10 ** 18);
return true;
}
/**
* @dev Put Chibi up for fusion, this will not destroy your Chibi. Only adults can fuse.
* @param _tokenId Id of Chibi token that is for fusion
* @param _price Price for the chibi in wei
*/
function setChibiForFusion(uint _tokenId, uint _price) public returns (bool success) {
require(ownerOf(_tokenId) == msg.sender);
require(_price >= priceFusionChibi);
require(chibies[_tokenId].adult <= now);
require(chibies[_tokenId].exhausted <= now);
require(chibies[_tokenId].forFusion == false);
require(battleContract.isDead(_tokenId) == false);
chibies[_tokenId].forFusion = true;
chibies[_tokenId].fusionPrice = _price;
emit ChibiForFusion(_tokenId, _price);
return true;
}
function cancelChibiForFusion(uint _tokenId) public returns (bool success) {
if (ownerOf(_tokenId) != msg.sender && msg.sender != address(battleRemoveContractAddress)) {
revert();
}
require(chibies[_tokenId].forFusion == true);
chibies[_tokenId].forFusion = false;
emit ChibiForFusionCancelled(_tokenId);
return false;
}
/**
* @dev Connect to gene contract. That way we can update that contract and add more fighters.
*/
function setGeneContractAddress(address _address) external contract_onlyOwner returns (bool success) {
geneContract = GeneInterface(_address);
return true;
}
/**
* @dev Fusions cost too much so they are here
* @return All the fusions (babies) of tokenId
*/
function queryFusionData(uint _tokenId) public view returns (
uint256[] fusions,
bool forFusion,
uint256 costFusion,
uint256 adult,
uint exhausted
) {
return (
chibies[_tokenId].fusions,
chibies[_tokenId].forFusion,
chibies[_tokenId].fusionPrice,
chibies[_tokenId].adult,
chibies[_tokenId].exhausted
);
}
/**
* @dev Minimal query for battle contract
* @return If for fusion
*/
function queryFusionData_ext(uint _tokenId) public view returns (
bool forFusion,
uint fusionPrice
) {
return (
chibies[_tokenId].forFusion,
chibies[_tokenId].fusionPrice
);
}
/**
* @dev Triggers a Chibi event to get some data of token
* @return various
*/
function queryChibi(uint _tokenId) public view returns (
string nameChibi,
string infoUrl,
uint16[13] dna,
uint256 father,
uint256 mother,
uint gen,
uint adult
) {
return (
chibies[_tokenId].nameChibi,
chibies[_tokenId].infoUrl,
chibies[_tokenId].dna,
chibies[_tokenId].father,
chibies[_tokenId].mother,
chibies[_tokenId].gen,
chibies[_tokenId].adult
);
}
/**
* @dev Triggers a Chibi event getting some additional data
* @return various
*/
function queryChibiAdd(uint _tokenId) public view returns (
address owner,
bool founder
) {
return (
chibies[_tokenId].owner,
chibies[_tokenId].founder
);
}
// exhaust after battle
function exhaustBattle(uint _tokenId) internal view returns (uint) {
uint _exhaust = 0;
for (uint i=10; i<13; i++) {
if (chibies[_tokenId].dna[i] == 1) {
_exhaust += (exhaustionTime * 3);
}
if (chibies[_tokenId].dna[i] == 3) {
_exhaust += exhaustionTime.div(2);
}
}
_exhaust = geneContract.exhaustAfterBattle(chibies[_tokenId].gen, _exhaust);
return _exhaust;
}
// exhaust after fusion
function exhaustFusion(uint _tokenId) internal returns (uint) {
uint _exhaust = 0;
uint counter = chibies[_tokenId].dna[9];
// set dna here, that way boni still apply but not infinite fusions possible
// max value 9999
if (chibies[_tokenId].dna[9] < 9999) chibies[_tokenId].dna[9]++;
for (uint i=10; i<13; i++) {
if (chibies[_tokenId].dna[i] == 2) {
counter = counter.sub(1);
}
if (chibies[_tokenId].dna[i] == 4) {
counter++;
}
}
_exhaust = geneContract.exhaustAfterFusion(chibies[_tokenId].gen, counter, exhaustionTime);
return _exhaust;
}
/**
* @dev Exhaust Chibis after battle
*/
function exhaustChibis(uint _tokenId1, uint _tokenId2) public returns (bool success) {
require(msg.sender == battleContractAddress);
chibies[_tokenId1].exhausted = now.add(exhaustBattle(_tokenId1));
chibies[_tokenId2].exhausted = now.add(exhaustBattle(_tokenId2));
return true;
}
/**
* @dev Split traits between father and mother and leave the random at the _tokenId2
*/
function traits(uint16[13] memory genes, uint _seed, uint _fatherId, uint _motherId) internal view returns (uint16[13] memory) {
uint _switch = uint136(keccak256(_seed, block.coinbase, block.timestamp)) % 5;
if (_switch == 0) {
genes[10] = chibies[_fatherId].dna[10];
genes[11] = chibies[_motherId].dna[11];
}
if (_switch == 1) {
genes[10] = chibies[_motherId].dna[10];
genes[11] = chibies[_fatherId].dna[11];
}
if (_switch == 2) {
genes[10] = chibies[_fatherId].dna[10];
genes[11] = chibies[_fatherId].dna[11];
}
if (_switch == 3) {
genes[10] = chibies[_motherId].dna[10];
genes[11] = chibies[_motherId].dna[11];
}
return genes;
}
/**
* @dev The fusion chamber combines both dnas and adds a generation.
*/
function fusionChibis(uint _fatherId, uint _motherId, uint _seed, string _name, string _battleRoar, uint8 _region) payable public returns (bool success) {
require(fusionPaused == false);
require(ownerOf(_fatherId) == msg.sender);
require(ownerOf(_motherId) != msg.sender);
require(chibies[_fatherId].adult <= now);
require(chibies[_fatherId].exhausted <= now);
require(chibies[_motherId].adult <= now);
require(chibies[_motherId].exhausted <= now);
require(chibies[_motherId].forFusion == true);
require(chibies[_motherId].fusionPrice == msg.value);
// exhaust father and mother
chibies[_motherId].forFusion = false;
chibies[_motherId].exhausted = now.add(exhaustFusion(_motherId));
chibies[_fatherId].exhausted = now.add(exhaustFusion(_fatherId));
uint _gen = 0;
if (chibies[_fatherId].gen >= chibies[_motherId].gen) {
_gen = chibies[_fatherId].gen.add(1);
} else {
_gen = chibies[_motherId].gen.add(1);
}
// fusion chamber here we come
uint16[13] memory dna = traits(geneContract.splitGenes(address(this), _seed, uniqueCounter+1), _seed, _fatherId, _motherId);
// new Chibi is born!
addToken(msg.sender, uniqueCounter);
// father and mother get the chibi in their fusion list
chibies[_fatherId].fusions.push(uniqueCounter);
// only add if mother different than father, otherwise double entry
if (_fatherId != _motherId) {
chibies[_motherId].fusions.push(uniqueCounter);
}
// baby Chibi won't have fusions
uint[] memory _fusions;
// baby Chibis can't be fused
chibies.push(Chibi(
msg.sender,
false,
_name,
dna,
_fatherId,
_motherId,
_gen,
_fusions,
false,
priceFusionChibi,
0,
now.add(adultTime.mul((_gen.mul(_gen)).add(1))),
strConcat(_infoUrlPrefix, uint2str(uniqueCounter))
));
// fires chibi created event
emit ChibiCreated(
uniqueCounter,
chibies[uniqueCounter].owner,
chibies[uniqueCounter].founder,
chibies[uniqueCounter].nameChibi,
chibies[uniqueCounter].dna,
chibies[uniqueCounter].father,
chibies[uniqueCounter].mother,
chibies[uniqueCounter].gen,
chibies[uniqueCounter].adult,
chibies[uniqueCounter].infoUrl
);
// send transfer event
emit Transfer(0x0, msg.sender, uniqueCounter);
// create Warrior
if (battleContract.addWarrior(address(this), uniqueCounter, _region, _battleRoar) == false) revert();
uniqueCounter ++;
// transfer money to seller minus our share, remain stays in contract
uint256 amount = msg.value / 100 * comission;
chibies[_motherId].owner.transfer(amount);
return true;
}
/**
* @dev Guarantees msg.sender is owner of the given token
* @param _tokenId uint256 ID of the token to validate its ownership belongs to msg.sender
*/
modifier onlyOwnerOf(uint256 _tokenId) {
require(ownerOf(_tokenId) == msg.sender);
_;
}
/**
* @dev Gets the total amount of tokens stored by the contract
* @return uint256 representing the total amount of tokens
*/
function totalSupply() public view returns (uint256) {
return totalTokens;
}
/**
* @dev Gets the balance of the specified address
* @param _owner address to query the balance of
* @return uint256 representing the amount owned by the passed address
*/
function balanceOf(address _owner) public view returns (uint256) {
return ownedTokens[_owner].length;
}
/**
* @dev Gets the list of tokens owned by a given address
* @param _owner address to query the tokens of
* @return uint256[] representing the list of tokens owned by the passed address
*/
function tokensOf(address _owner) public view returns (uint256[]) {
return ownedTokens[_owner];
}
/**
* @dev Gets the owner of the specified token ID
* @param _tokenId uint256 ID of the token to query the owner of
* @return owner address currently marked as the owner of the given token ID
*/
function ownerOf(uint256 _tokenId) public view returns (address) {
address owner = tokenOwner[_tokenId];
require(owner != address(0));
return owner;
}
/**
* @dev Gets the approved address to take ownership of a given token ID
* @param _tokenId uint256 ID of the token to query the approval of
* @return address currently approved to take ownership of the given token ID
*/
function approvedFor(uint256 _tokenId) public view returns (address) {
return tokenApprovals[_tokenId];
}
/**
* @dev Transfers the ownership of a given token ID to another address
* @param _to address to receive the ownership of the given token ID
* @param _tokenId uint256 ID of the token to be transferred
*/
function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
clearApprovalAndTransfer(msg.sender, _to, _tokenId);
}
/**
* @dev Approves another address to claim for the ownership of the given token ID
* @param _to address to be approved for the given token ID
* @param _tokenId uint256 ID of the token to be approved
*/
function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
address owner = ownerOf(_tokenId);
require(_to != owner);
if (approvedFor(_tokenId) != 0 || _to != 0) {
tokenApprovals[_tokenId] = _to;
emit Approval(owner, _to, _tokenId);
}
}
/**
* @dev Claims the ownership of a given token ID
* @param _tokenId uint256 ID of the token being claimed by the msg.sender
*/
function takeOwnership(uint256 _tokenId) public {
require(isApprovedFor(msg.sender, _tokenId));
clearApprovalAndTransfer(ownerOf(_tokenId), msg.sender, _tokenId);
}
function mintSpecial(string _name, string _battleRoar, uint8 _region, uint _seed, uint _specialId) public contract_onlyOwner returns (bool success) {
// name can be empty
_mint(_name, _battleRoar, _region, _seed, false, _specialId);
return true;
}
/**
* @dev Mint token function
* @param _name name of the Chibi
*/
function _mint(string _name, string _battleRoar, uint8 _region, uint _seed, bool _founder, uint _specialId) internal {
require(msg.sender != address(0));
addToken(msg.sender, uniqueCounter);
// creates a gen0 Chibi, no father, mother, gen0
uint16[13] memory dna;
if (_specialId > 0) {
dna = geneContract.createGenes(address(this), _seed, _founder, uniqueCounter, _specialId);
} else {
dna = geneContract.createGenes(address(this), _seed, _founder, uniqueCounter, 0);
}
uint[] memory _fusions;
chibies.push(Chibi(
msg.sender,
_founder,
_name,
dna,
0,
0,
0,
_fusions,
false,
priceFusionChibi,
0,
now.add(adultTime),
strConcat(_infoUrlPrefix, uint2str(uniqueCounter))
));
// send transfer event
emit Transfer(0x0, msg.sender, uniqueCounter);
// create Warrior
if (battleContract.addWarrior(address(this), uniqueCounter, _region, _battleRoar) == false) revert();
// fires chibi created event
emit ChibiCreated(
uniqueCounter,
chibies[uniqueCounter].owner,
chibies[uniqueCounter].founder,
chibies[uniqueCounter].nameChibi,
chibies[uniqueCounter].dna,
chibies[uniqueCounter].father,
chibies[uniqueCounter].mother,
chibies[uniqueCounter].gen,
chibies[uniqueCounter].adult,
chibies[uniqueCounter].infoUrl
);
uniqueCounter ++;
}
/**
* @dev buy gen0 chibis
* @param _name name of the Chibi
*/
function buyGEN0Chibi(string _name, string _battleRoar, uint8 _region, uint _seed) payable public returns (bool success) {
require(paused == false);
// cost at least 100 wei
require(msg.value == priceChibi);
// name can be empty
_mint(_name, _battleRoar, _region, _seed, false, 0);
return true;
}
/**
* @dev set default sale price of Chibies
* @param _priceChibi price of 1 Chibi in Wei
*/
function setChibiGEN0Price(uint _priceChibi) public contract_onlyOwner returns (bool success) {
priceChibi = _priceChibi;
return true;
}
/**
* @dev Tells whether the msg.sender is approved for the given token ID or not
* This function is not private so it can be extended in further implementations like the operatable ERC721
* @param _owner address of the owner to query the approval of
* @param _tokenId uint256 ID of the token to query the approval of
* @return bool whether the msg.sender is approved for the given token ID or not
*/
function isApprovedFor(address _owner, uint256 _tokenId) internal view returns (bool) {
return approvedFor(_tokenId) == _owner;
}
/**
* @dev Internal function to clear current approval and transfer the ownership of a given token ID
* @param _from address which you want to send tokens from
* @param _to address which you want to transfer the token to
* @param _tokenId uint256 ID of the token to be transferred
*/
function clearApprovalAndTransfer(address _from, address _to, uint256 _tokenId) internal {
require(_to != address(0));
require(_to != ownerOf(_tokenId));
require(ownerOf(_tokenId) == _from);
clearApproval(_from, _tokenId);
removeToken(_from, _tokenId);
addToken(_to, _tokenId);
// Chibbi code
chibies[_tokenId].owner = _to;
chibies[_tokenId].forFusion = false;
emit Transfer(_from, _to, _tokenId);
}
/**
* @dev Internal function to clear current approval of a given token ID
* @param _tokenId uint256 ID of the token to be transferred
*/
function clearApproval(address _owner, uint256 _tokenId) private {
require(ownerOf(_tokenId) == _owner);
tokenApprovals[_tokenId] = 0;
emit Approval(_owner, 0, _tokenId);
}
/**
* @dev Internal function to add a token ID to the list of a given address
* @param _to address representing the new owner of the given token ID
* @param _tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function addToken(address _to, uint256 _tokenId) private {
require(tokenOwner[_tokenId] == address(0));
tokenOwner[_tokenId] = _to;
uint256 length = balanceOf(_to);
ownedTokens[_to].push(_tokenId);
ownedTokensIndex[_tokenId] = length;
totalTokens++;
}
/**
* @dev Internal function to remove a token ID from the list of a given address
* @param _from address representing the previous owner of the given token ID
* @param _tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function removeToken(address _from, uint256 _tokenId) private {
require(ownerOf(_tokenId) == _from);
uint256 tokenIndex = ownedTokensIndex[_tokenId];
uint256 lastTokenIndex = balanceOf(_from).sub(1);
uint256 lastToken = ownedTokens[_from][lastTokenIndex];
tokenOwner[_tokenId] = 0;
ownedTokens[_from][tokenIndex] = lastToken;
ownedTokens[_from][lastTokenIndex] = 0;
// Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
// be zero. Then we can make sure that we will remove _tokenId from the ownedTokens list since we are first swapping
// the lastToken to the first position, and then dropping the element placed in the last position of the list
ownedTokens[_from].length--;
ownedTokensIndex[_tokenId] = 0;
ownedTokensIndex[lastToken] = tokenIndex;
totalTokens = totalTokens.sub(1);
}
/**
* @dev Send Ether to owner
* @param _address Receiving address
* @param amount Amount in WEI to send
**/
function weiToOwner(address _address, uint amount) public contract_onlyOwner {
require(amount <= address(this).balance);
_address.transfer(amount);
}
/**
* @dev Return the infoUrl of Chibi
* @param _tokenId infoUrl of _tokenId
**/
function tokenMetadata(uint256 _tokenId) constant public returns (string infoUrl) {
return chibies[_tokenId].infoUrl;
}
function tokenURI(uint256 _tokenId) public view returns (string) {
return chibies[_tokenId].infoUrl;
}
//
// some helpful functions
// https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol
//
function uint2str(uint i) internal pure returns (string) {
if (i == 0) return "0";
uint j = i;
uint len;
while (j != 0){
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (i != 0){
bstr[k--] = byte(48 + i % 10);
i /= 10;
}
return string(bstr);
}
function strConcat(string _a, string _b) internal pure returns (string) {
bytes memory _ba = bytes(_a);
bytes memory _bb = bytes(_b);
string memory ab = new string(_ba.length + _bb.length);
bytes memory bab = bytes(ab);
uint k = 0;
for (uint i = 0; i < _ba.length; i++) bab[k++] = _ba[i];
for (i = 0; i < _bb.length; i++) bab[k++] = _bb[i];
return string(bab);
}
}