文件 1 的 25:AccessControl.sol
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 25:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 3 的 25:Base64.sol
pragma solidity ^0.8.0;
library Base64 {
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function encode(bytes memory data) internal pure returns (string memory) {
if (data.length == 0) return "";
string memory table = _TABLE;
string memory result = new string(4 * ((data.length + 2) / 3));
assembly {
let tablePtr := add(table, 1)
let resultPtr := add(result, 32)
for {
let dataPtr := data
let endPtr := add(data, mload(data))
} lt(dataPtr, endPtr) {
} {
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
resultPtr := add(resultPtr, 1)
}
switch mod(mload(data), 3)
case 1 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case 2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}
文件 4 的 25:CharacterActivity.sol
pragma solidity ^0.8.0;
import "./CharacterStats.sol";
contract CharacterActivity is CharacterStats {
mapping(uint256 => Activity) public charactersActivity;
event ActivityStatusUpdated(address indexed account, uint256 indexed tokenID, bool active);
event ActivityStarted(address indexed account, uint256 indexed tokenID, Activity activity);
function _updateActivityStatus(uint256 tokenID, bool active)
internal
{
emit ActivityStatusUpdated(_msgSender(), tokenID, active);
charactersActivity[tokenID].active = active;
if (!active) {
charactersActivity[tokenID].completedBlock = block.number;
}
}
function _startActivity(uint256 tokenID, Activity calldata activity)
internal
{
require(activity.endBlock > activity.startBlock, "End block should be higher than start");
emit ActivityStarted(_msgSender(), tokenID, activity);
charactersActivity[tokenID] = activity;
}
function getBlocksUntilActivityEnds(uint256 tokenID)
external
view
returns (
uint256 blocksRemaining
)
{
Activity storage activity = charactersActivity[tokenID];
if (activity.endBlock > block.number) {
return activity.endBlock - block.number;
}
}
}
文件 5 的 25:CharacterManager.sol
pragma solidity >=0.8.0;
import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "./CollectionManager.sol";
contract CharacterManager is CollectionManager {
mapping (bytes32 => WrappedToken) public wrappedToken;
mapping (uint256 => bytes32) public wrappedTokenHashByID;
mapping (bytes32 => uint256) public tokenIDByHash;
event Wrapped(address indexed account, address indexed collection, uint256 blockNumber, uint256 wrappedTokenID, uint256 tokenID, bytes32 wrappedTokenHash);
event Unwrapped(address indexed account, address indexed collection, uint256 blockNumber, uint256 wrappedTokenID, uint256 tokenID, bytes32 wrappedTokenHash);
function _wrap(address account, address collectionAddress, uint256 wrappedTokenID, uint256 tokenID)
internal
isRegistered(collectionAddress)
{
bytes32 wrappedTokenHash = hashWrappedToken(collectionAddress, wrappedTokenID);
if (isNeverWrapped(collectionAddress, wrappedTokenID)) {
wrappedToken[wrappedTokenHash].collectionAddress = collectionAddress;
wrappedToken[wrappedTokenHash].wrappedTokenID = wrappedTokenID;
wrappedTokenHashByID[tokenID] = wrappedTokenHash;
tokenIDByHash[wrappedTokenHash] = tokenID;
}
wrappedToken[wrappedTokenHash].status = WrappedStatus.Wrapped;
emit Wrapped(account, collectionAddress, block.number, wrappedTokenID, tokenID, wrappedTokenHash);
IERC721(collectionAddress).safeTransferFrom(account, address(this), wrappedTokenID);
}
function _unwrap(uint256 tokenID)
internal
{
(address collectionAddress, uint256 wrappedTokenID, WrappedStatus status) = getWrappedTokenDetails(tokenID);
require(status == WrappedStatus.Wrapped, "There is no token to unwrap");
bytes32 wrappedTokenHash = hashWrappedToken(collectionAddress, wrappedTokenID);
wrappedToken[wrappedTokenHash].status = WrappedStatus.Unwrapped;
emit Unwrapped(_msgSender(), collectionAddress, block.number, wrappedTokenID, tokenID, wrappedTokenHash);
IERC721(collectionAddress).safeTransferFrom(address(this), _msgSender(), wrappedTokenID);
}
function getWrappedTokenDetails(uint256 tokenID)
public
view
returns (
address collectionAddress,
uint256 wrappedTokenID,
WrappedStatus status
)
{
return (wrappedToken[wrappedTokenHashByID[tokenID]].collectionAddress,
wrappedToken[wrappedTokenHashByID[tokenID]].wrappedTokenID,
wrappedToken[wrappedTokenHashByID[tokenID]].status
);
}
function isWrapped(address collectionAddress, uint256 wrappedTokenID)
external
view
returns (
bool tokenIsWrapped
)
{
if (wrappedToken[hashWrappedToken(collectionAddress, wrappedTokenID)].status == WrappedStatus.Wrapped) {
return (true);
}
}
function isNeverWrapped(address collectionAddress, uint256 wrappedTokenID)
public
view
returns (
bool tokenNeverWrapped
)
{
if (wrappedToken[hashWrappedToken(collectionAddress, wrappedTokenID)].status == WrappedStatus.NeverWrapped) {
return (true);
}
}
function hashWrappedToken(address collectionAddress, uint256 wrappedTokenID)
public
pure
returns (
bytes32 wrappedTokenHash
)
{
wrappedTokenHash = keccak256(abi.encodePacked(collectionAddress, wrappedTokenID));
}
}
文件 6 的 25:CharacterStats.sol
pragma solidity >=0.8.0;
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
import "../characters/interfaces/IFarmlandCollectible.sol";
import "./CharacterManager.sol";
contract CharacterStats is CharacterManager {
using SafeCast for uint256;
mapping(bytes32 => uint16[]) public stats;
mapping(uint256 => uint16) public getStatBoosted;
uint16 public statsPerLevel = 3;
event StatIncreased(address indexed account, uint256 tokenID, uint256 amount, uint256 statIndex);
event StatDecreased(address indexed account, uint256 tokenID, uint256 amount, uint256 statIndex);
function _increaseStat(uint256 tokenID, uint256 amount, uint256 statIndex)
internal
{
bytes32 wrappedTokenHash = wrappedTokenHashByID[tokenID];
uint16 currentStat = stats[wrappedTokenHash][statIndex];
uint16 maxStat = 99;
if (statIndex == 5) {
maxStat = getMaxHealth(tokenID).toUint16();
} else if (statIndex == 6) {
maxStat = getMaxMorale(tokenID).toUint16();
} else if (statIndex > 6) {
maxStat = 10000;
}
require(currentStat != maxStat, "Stat already at maximum");
if (currentStat + amount.toUint16() < maxStat + 1) {
stats[wrappedTokenHash][statIndex] += amount.toUint16();
} else {
stats[wrappedTokenHash][statIndex] = maxStat;
}
emit StatIncreased(_msgSender(), tokenID, amount, statIndex);
}
function _decreaseStat(uint256 tokenID, uint256 amount, uint256 statIndex)
internal
{
bytes32 wrappedTokenHash = wrappedTokenHashByID[tokenID];
uint16 currentStat = stats[wrappedTokenHash][statIndex];
if (currentStat > amount.toUint16()) {
stats[wrappedTokenHash][statIndex] -= amount.toUint16();
} else {
stats[wrappedTokenHash][statIndex] = 1;
}
emit StatDecreased(_msgSender(), tokenID, amount, statIndex);
}
function _setStatTo(uint256 tokenID, uint256 amount, uint256 statIndex)
internal
{
bytes32 wrappedTokenHash = wrappedTokenHashByID[tokenID];
uint16 currentStat = stats[wrappedTokenHash][statIndex];
if (amount.toUint16() > currentStat) {
_increaseStat(tokenID, amount.toUint16() - currentStat, statIndex);
} else {
_decreaseStat(tokenID, currentStat - amount, statIndex);
}
}
function _boostStat(uint256 tokenID, uint256 amount, uint256 statIndex)
internal
{
require(statIndex < 5, "Invalid Stat");
require(amount <= getStatBoostAvailable(tokenID), "This will exceed the available boosts for this character");
getStatBoosted[tokenID] += amount.toUint16();
_increaseStat(tokenID, amount ,statIndex);
}
function _storeStats(address collectionAddress, uint256 wrappedTokenID)
internal
isRegistered(collectionAddress)
{
uint256 stamina; uint256 strength; uint256 speed; uint256 courage; uint256 intelligence; uint256 health; uint256 morale;
bytes32 wrappedTokenHash = hashWrappedToken(collectionAddress, wrappedTokenID);
require(stats[wrappedTokenHash].length == 0, "Traits can be created once");
if (characterCollections[collectionAddress].native) {
(, stamina, strength, speed, courage, intelligence) = IFarmlandCollectible(collectionAddress).collectibleTraits(wrappedTokenID);
} else {
uint256 range = characterCollections[collectionAddress].range;
uint256 offset = characterCollections[collectionAddress].offset;
uint256[] memory randomNumbers = new uint256[](5);
randomNumbers = _getRandomNumbers(5, wrappedTokenID);
stamina = (randomNumbers[0] % range) + offset;
strength = (randomNumbers[1] % range) + offset;
speed = (randomNumbers[2] % range) + offset;
courage = (randomNumbers[3] % range) + offset;
intelligence = (randomNumbers[4] % range) + offset;
}
health = (strength + stamina) / 2;
if (strength > 95 || stamina > 95)
{
health += health / 2;
}
morale = (courage + intelligence) / 2 ;
if (courage > 95 || intelligence > 95)
{
morale += morale / 2;
}
stats[wrappedTokenHash] = [
stamina.toUint16(),
strength.toUint16(),
speed.toUint16(),
courage.toUint16(),
intelligence.toUint16(),
health.toUint16(),
morale.toUint16(),
0];
}
function _getRandomNumbers(uint256 n, uint256 salt)
internal
view
returns (uint256[] memory randomNumbers)
{
randomNumbers = new uint256[](n);
for (uint256 i = 0; i < n;) {
randomNumbers[i] = uint256(keccak256(abi.encodePacked(block.timestamp, salt, i)));
unchecked { i++; }
}
}
function updateStatsPerLevel(uint256 newStatsPerLevel)
external
onlyOwner
{
statsPerLevel = newStatsPerLevel.toUint16();
}
function getStats(uint256 tokenID)
public
view
returns (
uint256 stamina, uint256 strength, uint256 speed, uint256 courage, uint256 intelligence, uint256 health, uint256 morale, uint256 experience, uint256 level
)
{
bytes32 wrappedTokenHash = wrappedTokenHashByID[tokenID];
uint256 total = stats[wrappedTokenHash].length;
if (total > 7) {
stamina = stats[wrappedTokenHash][0];
strength = stats[wrappedTokenHash][1];
speed = stats[wrappedTokenHash][2];
courage = stats[wrappedTokenHash][3];
intelligence = stats[wrappedTokenHash][4];
health = stats[wrappedTokenHash][5];
morale = stats[wrappedTokenHash][6];
experience = stats[wrappedTokenHash][7];
level = sqrt(experience);
} else {
return (0,0,0,0,0,0,0,0,0);
}
}
function getLevel(uint256 tokenID)
public
view
returns (
uint256 level
)
{
bytes32 wrappedTokenHash = wrappedTokenHashByID[tokenID];
return sqrt(stats[wrappedTokenHash][7]);
}
function sqrt(uint256 y)
internal
pure
returns (
uint256 z
)
{
if (y > 3) {
z = y;
uint x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
function getMaxHealth(uint256 tokenID)
public
view
returns (
uint256 health
)
{
(uint256 stamina, uint256 strength,,,,,,,) = getStats(tokenID);
health = (strength + stamina) / 2;
if (strength > 95 || stamina > 95)
{
health += health / 2;
}
}
function getMaxMorale(uint256 tokenID)
public
view
returns (
uint256 morale
)
{
(,,,uint256 courage, uint256 intelligence,,,,) = getStats(tokenID);
morale = (courage + intelligence) / 2 ;
if (courage > 95 || intelligence > 95)
{
morale += morale / 2;
}
}
function getStatBoostAvailable(uint256 tokenID)
public
view
returns (uint256 statBoost)
{
return (getLevel(tokenID) * statsPerLevel) - getStatBoosted[tokenID];
}
}
文件 7 的 25:CollectionManager.sol
pragma solidity ^0.8.0;
import "./interfaces/IWrappedCharacters.sol";
import "../utils/Permissioned.sol";
contract CollectionManager is Permissioned {
constructor () Permissioned() {}
mapping(address => Collection) public characterCollections;
modifier isRegistered(address collectionAddress) {
require(isCollectionEnabled(collectionAddress) || collectionAddress == address(this),"This collection is not registered");
_;
}
modifier isWrappable(address collectionAddress) {
require(isCollectionEnabled(collectionAddress) && collectionAddress != address(this),"This collection is not wrappable");
_;
}
event CollectionEnabled(address indexed account, address collectionAddress, bool native, uint256 range, uint256 offset);
event CollectionDisabled(address indexed account, address collectionAddress);
function enableCollection(address collectionAddress, bool native, uint256 range, uint256 offset)
external
onlyOwner
{
characterCollections[collectionAddress].native = native;
characterCollections[collectionAddress].range = range;
characterCollections[collectionAddress].offset = offset;
emit CollectionEnabled(_msgSender(), collectionAddress, native, range, offset);
}
function disableCollection(address collectionAddress)
external
onlyOwner
{
delete characterCollections[collectionAddress];
emit CollectionDisabled(_msgSender(), collectionAddress);
}
function isCollectionEnabled(address collectionAddress)
public
view
returns (
bool enabled
)
{
if (characterCollections[collectionAddress].range > 0) {
return true;
}
}
}
文件 8 的 25:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 9 的 25:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 10 的 25:ERC721.sol
pragma solidity ^0.8.0;
import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
using Address for address;
using Strings for uint256;
string private _name;
string private _symbol;
mapping(uint256 => address) private _owners;
mapping(address => uint256) private _balances;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address owner) public view virtual override returns (uint256) {
require(owner != address(0), "ERC721: address zero is not a valid owner");
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ERC721: invalid token ID");
return owner;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
_requireMinted(tokenId);
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
function _baseURI() internal view virtual returns (string memory) {
return "";
}
function approve(address to, uint256 tokenId) public virtual override {
address owner = ERC721.ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not token owner nor approved for all"
);
_approve(to, tokenId);
}
function getApproved(uint256 tokenId) public view virtual override returns (address) {
_requireMinted(tokenId);
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner nor approved");
_transfer(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory data
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner nor approved");
_safeTransfer(from, to, tokenId, data);
}
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory data
) internal virtual {
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
}
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
function _safeMint(
address to,
uint256 tokenId,
bytes memory data
) internal virtual {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
_afterTokenTransfer(address(0), to, tokenId);
}
function _burn(uint256 tokenId) internal virtual {
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
_approve(address(0), tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
_afterTokenTransfer(owner, address(0), tokenId);
}
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
_afterTokenTransfer(from, to, tokenId);
}
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
require(owner != operator, "ERC721: approve to caller");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
function _requireMinted(uint256 tokenId) internal view virtual {
require(_exists(tokenId), "ERC721: invalid token ID");
}
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory data
) private returns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
}
文件 11 的 25:ERC721Holder.sol
pragma solidity ^0.8.0;
import "../IERC721Receiver.sol";
contract ERC721Holder is IERC721Receiver {
function onERC721Received(
address,
address,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC721Received.selector;
}
}
文件 12 的 25:IAccessControl.sol
pragma solidity ^0.8.0;
interface IAccessControl {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 13 的 25:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 14 的 25:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface 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) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool _approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
文件 15 的 25:IERC721Enumerable.sol
pragma solidity ^0.8.0;
import "../IERC721.sol";
interface IERC721Enumerable is IERC721 {
function totalSupply() external view returns (uint256);
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
function tokenByIndex(uint256 index) external view returns (uint256);
}
文件 16 的 25:IERC721Metadata.sol
pragma solidity ^0.8.0;
import "../IERC721.sol";
interface IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
文件 17 的 25:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 18 的 25:IFarmlandCollectible.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
struct CollectibleTraits {uint256 expiryDate; uint256 trait1; uint256 trait2; uint256 trait3; uint256 trait4; uint256 trait5;}
struct CollectibleSlots {uint256 slot1; uint256 slot2; uint256 slot3; uint256 slot4; uint256 slot5; uint256 slot6; uint256 slot7; uint256 slot8;}
abstract contract IFarmlandCollectible is IERC721Enumerable, IERC721Metadata {
mapping(uint256 => CollectibleTraits) public collectibleTraits;
mapping(uint256 => CollectibleSlots) public collectibleSlots;
function setCollectibleSlot(uint256 id, uint256 slotIndex, uint256 slot) external virtual;
function walletOfOwner(address account) external view virtual returns(uint256[] memory tokenIds);
}
文件 19 的 25:IWrappedCharacters.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
enum WrappedStatus {NeverWrapped, Wrapped, Unwrapped}
struct Collection {bool native; uint256 range; uint256 offset;}
struct WrappedToken {address collectionAddress; uint256 wrappedTokenID; WrappedStatus status;}
struct Activity {bool active; uint256 numberOfActivities; uint256 activityDuration; uint256 startBlock; uint256 endBlock; uint256 completedBlock;}
abstract contract IWrappedCharacters is IERC721 {
mapping(bytes32 => uint16[]) public stats;
mapping (uint256 => Activity) public charactersActivity;
mapping (bytes32 => WrappedToken) public wrappedToken;
mapping (uint256 => bytes32) public wrappedTokenHashByID;
mapping (bytes32 => uint256) public tokenIDByHash;
mapping(uint256 => uint16) public getStatBoosted;
function wrap(uint256 wrappedTokenID, address collectionAddress) external virtual;
function unwrap(uint256 tokenID) external virtual;
function updateActivityStatus(uint256 tokenID, bool active) external virtual;
function startActivity(uint256 tokenID, Activity calldata activity) external virtual;
function setStatTo(uint256 tokenID, uint256 amount, uint256 statIndex) external virtual;
function increaseStat(uint256 tokenID, uint256 amount, uint256 statIndex) external virtual;
function decreaseStat(uint256 tokenID, uint256 amount, uint256 statIndex) external virtual;
function boostStat(uint256 tokenID, uint256 amount, uint256 statIndex)external virtual;
function getBlocksUntilActivityEnds(uint256 tokenID) external virtual view returns (uint256 blocksRemaining);
function getMaxHealth(uint256 tokenID) external virtual view returns (uint256 health);
function getStats(uint256 tokenID) external virtual view returns (uint256 stamina, uint256 strength, uint256 speed, uint256 courage, uint256 intelligence, uint256 health, uint256 morale, uint256 experience, uint256 level);
function getLevel(uint256 tokenID) external virtual view returns (uint256 level);
function hashWrappedToken(address collectionAddress, uint256 wrappedTokenID) external virtual pure returns (bytes32 wrappedTokenHash);
function isWrapped(address collectionAddress, uint256 wrappedTokenID) external virtual view returns (bool tokenExists);
function getWrappedTokenDetails(uint256 tokenID) external virtual view returns (address collectionAddress, uint256 wrappedTokenID, WrappedStatus status);
}
文件 20 的 25:Mercenaries.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
import "./WrappedCharacters.sol";
contract Mercenaries is WrappedCharacters {
using Strings for uint256;
constructor (
string memory _initialBaseURI
)
WrappedCharacters("Farmland Mercenaries", "MERCENARIES") {
baseURI = _initialBaseURI;
}
mapping (uint256 => bytes16[]) public visualTraits;
event MercenaryMinted(address indexed account, uint256 indexed tokenID, bytes16[] traits);
event MercenaryTraitsUpdated(address indexed account, uint256 indexed tokenID, bytes16[] traits);
function mint(address to, bytes16[] calldata traits)
external
nonReentrant
onlyAllowed
{
unchecked { totalTokens++; }
uint256 tokenID = totalTokens;
emit MercenaryMinted(to, tokenID, traits);
_storeStats(address(this),tokenID);
bytes32 wrappedTokenHash = hashWrappedToken(address(this), tokenID);
wrappedToken[wrappedTokenHash].collectionAddress = address(this);
wrappedToken[wrappedTokenHash].wrappedTokenID = tokenID;
wrappedTokenHashByID[tokenID] = wrappedTokenHash;
visualTraits[tokenID] = traits;
_mint(to, tokenID);
}
function updateTraits(uint256 tokenID, bytes16[] calldata traits)
external
nonReentrant
onlyAllowed
onlyExists(tokenID)
{
emit MercenaryTraitsUpdated(_msgSender(), tokenID, traits);
visualTraits[tokenID] = traits;
}
function tokenURI(uint256 tokenID)
public
view
virtual
override(ERC721)
onlyExists(tokenID)
returns (string memory uri)
{
(address collectionAddress,uint256 wrappedTokenID,) = getWrappedTokenDetails(tokenID);
if (collectionAddress == address(this)) {
bytes32 wrappedTokenHash = hashWrappedToken(collectionAddress, wrappedTokenID);
uint256 level = getLevel(tokenID);
string memory _url = ERC721.tokenURI(tokenID);
string memory url = string(abi.encodePacked(_url,".png"));
string memory mercenaryName = string(abi.encodePacked("Mercenary #",Strings.toString(tokenID)));
string memory json1 = string(abi.encodePacked(
'{',
'"name": "', mercenaryName, '",',
'"description": "Mercenaries are available to hire for various activities",',
'"image": "', url, '",',
'"seller_fee_basis_points": 100,',
'"fee_recipient": "0xC74956f14b1C0F5057404A8A26D3074924545dF8",',
'"attributes": [',
'{ "id": 0, "trait_type": "Level", "value": "' ,Strings.toString(level), '" },'
));
string memory output = Base64.encode(abi.encodePacked(json1, encodeTraits(tokenID), encodeStats(wrappedTokenHash)));
return string(abi.encodePacked('data:application/json;base64,', output));
} else {
return IERC721Metadata(collectionAddress).tokenURI(wrappedTokenID);
}
}
function encodeTraits(uint256 tokenID)
internal
view
returns (string memory)
{
bytes16[] memory traits = visualTraits[tokenID];
string memory json1 = string(abi.encodePacked(
'{ "id": 0, "trait_type": "Background", "value": "' ,_bytes16ToString(traits[0]), '" },',
'{ "id": 0, "trait_type": "Base", "value": "' ,_bytes16ToString(traits[1]), '" },',
'{ "id": 0, "trait_type": "Gender", "value": "' ,_bytes16ToString(traits[2]), '" },',
'{ "id": 0, "trait_type": "Hair", "value": "' ,_bytes16ToString(traits[3]), '" },'
));
string memory json2 = string(abi.encodePacked(
'{ "id": 0, "trait_type": "Eyes", "value": "' ,_bytes16ToString(traits[4]), '" },',
'{ "id": 0, "trait_type": "Mouth", "value": "' ,_bytes16ToString(traits[5]), '" },',
'{ "id": 0, "trait_type": "Clothing", "value": "' ,_bytes16ToString(traits[6]), '" },',
'{ "id": 0, "trait_type": "Feature", "value": "' ,_bytes16ToString(traits[7]), '" },'
));
return string(abi.encodePacked(json1, json2));
}
function encodeStats(bytes32 wrappedTokenHash)
internal
view
returns (string memory)
{
uint16[] memory stat = stats[wrappedTokenHash];
string memory json1 = string(abi.encodePacked(
'{ "id": 0, "trait_type": "Stamina", "value": "' ,Strings.toString(stat[0]), '" },',
'{ "id": 0, "trait_type": "Strength", "value": "' ,Strings.toString(stat[1]), '" },',
'{ "id": 0, "trait_type": "Speed", "value": "' ,Strings.toString(stat[2]), '" },',
'{ "id": 0, "trait_type": "Courage", "value": "' ,Strings.toString(stat[3]), '" },'
));
string memory json2 = string(abi.encodePacked(
'{ "id": 0, "trait_type": "Intelligence", "value": "' ,Strings.toString(stat[4]), '" },',
'{ "id": 0, "trait_type": "Health", "value": "' ,Strings.toString(stat[5]), '" },',
'{ "id": 0, "trait_type": "Morale", "value": "' ,Strings.toString(stat[6]), '" },',
'{ "id": 0, "trait_type": "Experience", "value": "' ,Strings.toString(stat[7]), '" }',
']',
'}'
));
return string(abi.encodePacked(json1, json2));
}
function _bytes16ToString(bytes16 toConvert)
private
pure
returns (string memory)
{
uint8 i = 0;
while(i < 16 && toConvert[i] != 0) {
unchecked { i++; }
}
bytes memory bytesArray = new bytes(i);
for (i = 0; i < 16 && toConvert[i] != 0;) {
bytesArray[i] = toConvert[i];
unchecked { i++; }
}
return string(bytesArray);
}
function _baseURI()
internal
view
override(ERC721)
returns (string memory)
{
return baseURI;
}
function isMercenary(uint256 tokenID)
external
view
onlyExists(tokenID)
returns (bool mercenary)
{
(address collectionAddress,,) = getWrappedTokenDetails(tokenID);
if (collectionAddress == address(this)) {return true;}
}
function isCitizen(uint256 tokenID)
external
view
onlyExists(tokenID)
returns (bool citizen)
{
(address collectionAddress,,) = getWrappedTokenDetails(tokenID);
if (characterCollections[collectionAddress].native && collectionAddress != address(this)) {return true;}
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId)
internal
override(ERC721)
{
super._beforeTokenTransfer(from, to, tokenId);
require(!charactersActivity[tokenId].active, "Mercenary is active");
}
}
文件 21 的 25:Permissioned.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/AccessControl.sol";
contract Permissioned is AccessControl {
constructor () {
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
bytes32 public constant ACCESS_ROLE = keccak256("ACCESS_ROLE");
modifier onlyOwner() {
require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Caller is not the owner");
_;
}
modifier onlyAllowed() {
require(hasRole(ACCESS_ROLE, _msgSender()), "Caller does not have permission");
_;
}
function addAllowed(address account)
external virtual onlyOwner
{
grantRole(ACCESS_ROLE, account);
}
function addOwner(address account)
public virtual onlyOwner
{
grantRole(DEFAULT_ADMIN_ROLE, account);
}
function removeAllowed(address account)
external virtual onlyOwner
{
revokeRole(ACCESS_ROLE, account);
}
function transferOwnership(address newOwner)
external virtual onlyOwner
{
require(newOwner != address(0), "Permissioned: new owner is the zero address");
addOwner(newOwner);
renounceOwner();
}
function renounceOwner()
public virtual
{
renounceRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
function isOwner(address account)
external virtual view returns (bool)
{
return hasRole(DEFAULT_ADMIN_ROLE, account);
}
function isAllowed(address account)
external virtual view returns (bool)
{
return hasRole(ACCESS_ROLE, account);
}
}
文件 22 的 25:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 23 的 25:SafeCast.sol
pragma solidity ^0.8.0;
library SafeCast {
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
function toInt248(int256 value) internal pure returns (int248) {
require(value >= type(int248).min && value <= type(int248).max, "SafeCast: value doesn't fit in 248 bits");
return int248(value);
}
function toInt240(int256 value) internal pure returns (int240) {
require(value >= type(int240).min && value <= type(int240).max, "SafeCast: value doesn't fit in 240 bits");
return int240(value);
}
function toInt232(int256 value) internal pure returns (int232) {
require(value >= type(int232).min && value <= type(int232).max, "SafeCast: value doesn't fit in 232 bits");
return int232(value);
}
function toInt224(int256 value) internal pure returns (int224) {
require(value >= type(int224).min && value <= type(int224).max, "SafeCast: value doesn't fit in 224 bits");
return int224(value);
}
function toInt216(int256 value) internal pure returns (int216) {
require(value >= type(int216).min && value <= type(int216).max, "SafeCast: value doesn't fit in 216 bits");
return int216(value);
}
function toInt208(int256 value) internal pure returns (int208) {
require(value >= type(int208).min && value <= type(int208).max, "SafeCast: value doesn't fit in 208 bits");
return int208(value);
}
function toInt200(int256 value) internal pure returns (int200) {
require(value >= type(int200).min && value <= type(int200).max, "SafeCast: value doesn't fit in 200 bits");
return int200(value);
}
function toInt192(int256 value) internal pure returns (int192) {
require(value >= type(int192).min && value <= type(int192).max, "SafeCast: value doesn't fit in 192 bits");
return int192(value);
}
function toInt184(int256 value) internal pure returns (int184) {
require(value >= type(int184).min && value <= type(int184).max, "SafeCast: value doesn't fit in 184 bits");
return int184(value);
}
function toInt176(int256 value) internal pure returns (int176) {
require(value >= type(int176).min && value <= type(int176).max, "SafeCast: value doesn't fit in 176 bits");
return int176(value);
}
function toInt168(int256 value) internal pure returns (int168) {
require(value >= type(int168).min && value <= type(int168).max, "SafeCast: value doesn't fit in 168 bits");
return int168(value);
}
function toInt160(int256 value) internal pure returns (int160) {
require(value >= type(int160).min && value <= type(int160).max, "SafeCast: value doesn't fit in 160 bits");
return int160(value);
}
function toInt152(int256 value) internal pure returns (int152) {
require(value >= type(int152).min && value <= type(int152).max, "SafeCast: value doesn't fit in 152 bits");
return int152(value);
}
function toInt144(int256 value) internal pure returns (int144) {
require(value >= type(int144).min && value <= type(int144).max, "SafeCast: value doesn't fit in 144 bits");
return int144(value);
}
function toInt136(int256 value) internal pure returns (int136) {
require(value >= type(int136).min && value <= type(int136).max, "SafeCast: value doesn't fit in 136 bits");
return int136(value);
}
function toInt128(int256 value) internal pure returns (int128) {
require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
return int128(value);
}
function toInt120(int256 value) internal pure returns (int120) {
require(value >= type(int120).min && value <= type(int120).max, "SafeCast: value doesn't fit in 120 bits");
return int120(value);
}
function toInt112(int256 value) internal pure returns (int112) {
require(value >= type(int112).min && value <= type(int112).max, "SafeCast: value doesn't fit in 112 bits");
return int112(value);
}
function toInt104(int256 value) internal pure returns (int104) {
require(value >= type(int104).min && value <= type(int104).max, "SafeCast: value doesn't fit in 104 bits");
return int104(value);
}
function toInt96(int256 value) internal pure returns (int96) {
require(value >= type(int96).min && value <= type(int96).max, "SafeCast: value doesn't fit in 96 bits");
return int96(value);
}
function toInt88(int256 value) internal pure returns (int88) {
require(value >= type(int88).min && value <= type(int88).max, "SafeCast: value doesn't fit in 88 bits");
return int88(value);
}
function toInt80(int256 value) internal pure returns (int80) {
require(value >= type(int80).min && value <= type(int80).max, "SafeCast: value doesn't fit in 80 bits");
return int80(value);
}
function toInt72(int256 value) internal pure returns (int72) {
require(value >= type(int72).min && value <= type(int72).max, "SafeCast: value doesn't fit in 72 bits");
return int72(value);
}
function toInt64(int256 value) internal pure returns (int64) {
require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
return int64(value);
}
function toInt56(int256 value) internal pure returns (int56) {
require(value >= type(int56).min && value <= type(int56).max, "SafeCast: value doesn't fit in 56 bits");
return int56(value);
}
function toInt48(int256 value) internal pure returns (int48) {
require(value >= type(int48).min && value <= type(int48).max, "SafeCast: value doesn't fit in 48 bits");
return int48(value);
}
function toInt40(int256 value) internal pure returns (int40) {
require(value >= type(int40).min && value <= type(int40).max, "SafeCast: value doesn't fit in 40 bits");
return int40(value);
}
function toInt32(int256 value) internal pure returns (int32) {
require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
return int32(value);
}
function toInt24(int256 value) internal pure returns (int24) {
require(value >= type(int24).min && value <= type(int24).max, "SafeCast: value doesn't fit in 24 bits");
return int24(value);
}
function toInt16(int256 value) internal pure returns (int16) {
require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
return int16(value);
}
function toInt8(int256 value) internal pure returns (int8) {
require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
return int8(value);
}
function toInt256(uint256 value) internal pure returns (int256) {
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
文件 24 的 25:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
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);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
文件 25 的 25:WrappedCharacters.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./CharacterActivity.sol";
contract WrappedCharacters is CharacterActivity, ERC721, ERC721Holder, ReentrancyGuard {
constructor (string memory name_, string memory symbol_) ERC721(name_, symbol_) {}
uint256 internal totalTokens;
string public baseURI;
modifier onlyExists(uint256 tokenID) {
require (_exists(tokenID),"Character does not exist");
_;
}
modifier onlyOwnerOfToken(uint256 tokenID) {
require (ownerOf(tokenID) == _msgSender(),"Only the owner of the token can perform this action");
_;
}
function wrap(address account, uint256 wrappedTokenID, address collectionAddress)
external
nonReentrant
isWrappable(collectionAddress)
onlyAllowed
{
uint256 tokenID;
if (isNeverWrapped(collectionAddress, wrappedTokenID)) {
unchecked { totalTokens++; }
tokenID = totalTokens;
_storeStats(collectionAddress, wrappedTokenID);
} else {
tokenID = tokenIDByHash[hashWrappedToken(collectionAddress,wrappedTokenID)];
}
_wrap(account, collectionAddress, wrappedTokenID, tokenID);
_mint(account, tokenID);
}
function unwrap(uint256 tokenID)
external
nonReentrant
onlyExists(tokenID)
onlyOwnerOfToken(tokenID)
{
_burn(tokenID);
_unwrap(tokenID);
}
function increaseStat(uint256 tokenID, uint256 amount, uint256 statIndex)
external
onlyAllowed
onlyExists(tokenID)
{
_increaseStat(tokenID, amount, statIndex);
}
function decreaseStat(uint256 tokenID, uint256 amount, uint256 statIndex)
external
onlyAllowed
onlyExists(tokenID)
{
_decreaseStat(tokenID, amount, statIndex);
}
function setStatTo(uint256 tokenID, uint256 amount, uint256 statIndex)
external
onlyAllowed
onlyExists(tokenID)
{
_setStatTo(tokenID, amount, statIndex);
}
function boostStat(uint256 tokenID, uint256 amount, uint256 statIndex)
external
onlyAllowed
onlyExists(tokenID)
{
_boostStat(tokenID, amount, statIndex);
}
function updateActivityStatus(uint256 tokenID, bool active)
external
onlyAllowed
onlyExists(tokenID)
{
_updateActivityStatus (tokenID, active);
}
function startActivity(uint256 tokenID, Activity calldata activity)
external
onlyAllowed
onlyExists(tokenID)
{
_startActivity(tokenID, activity);
}
function setBaseURI(string memory uri)
external
onlyOwner
{
baseURI = uri;
}
function totalSupply() external view returns (uint256)
{
return totalTokens;
}
function supportsInterface(bytes4 interfaceId) public view virtual override (ERC721, AccessControl) returns (bool) {
return super.supportsInterface(interfaceId);
}
}
{
"compilationTarget": {
"project:/contracts/mercenaries/Mercenaries.sol": "Mercenaries"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"_initialBaseURI","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenID","type":"uint256"},{"components":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint256","name":"numberOfActivities","type":"uint256"},{"internalType":"uint256","name":"activityDuration","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"},{"internalType":"uint256","name":"completedBlock","type":"uint256"}],"indexed":false,"internalType":"struct Activity","name":"activity","type":"tuple"}],"name":"ActivityStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"ActivityStatusUpdated","type":"event"},{"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":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"collectionAddress","type":"address"}],"name":"CollectionDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"collectionAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"native","type":"bool"},{"indexed":false,"internalType":"uint256","name":"range","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"offset","type":"uint256"}],"name":"CollectionEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"bytes16[]","name":"traits","type":"bytes16[]"}],"name":"MercenaryMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"bytes16[]","name":"traits","type":"bytes16[]"}],"name":"MercenaryTraitsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"statIndex","type":"uint256"}],"name":"StatDecreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"statIndex","type":"uint256"}],"name":"StatIncreased","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"wrappedTokenID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"wrappedTokenHash","type":"bytes32"}],"name":"Unwrapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"wrappedTokenID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"wrappedTokenHash","type":"bytes32"}],"name":"Wrapped","type":"event"},{"inputs":[],"name":"ACCESS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addOwner","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":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"statIndex","type":"uint256"}],"name":"boostStat","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"characterCollections","outputs":[{"internalType":"bool","name":"native","type":"bool"},{"internalType":"uint256","name":"range","type":"uint256"},{"internalType":"uint256","name":"offset","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"charactersActivity","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint256","name":"numberOfActivities","type":"uint256"},{"internalType":"uint256","name":"activityDuration","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"},{"internalType":"uint256","name":"completedBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"statIndex","type":"uint256"}],"name":"decreaseStat","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collectionAddress","type":"address"}],"name":"disableCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collectionAddress","type":"address"},{"internalType":"bool","name":"native","type":"bool"},{"internalType":"uint256","name":"range","type":"uint256"},{"internalType":"uint256","name":"offset","type":"uint256"}],"name":"enableCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"getBlocksUntilActivityEnds","outputs":[{"internalType":"uint256","name":"blocksRemaining","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"getLevel","outputs":[{"internalType":"uint256","name":"level","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"getMaxHealth","outputs":[{"internalType":"uint256","name":"health","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"getMaxMorale","outputs":[{"internalType":"uint256","name":"morale","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"getStatBoostAvailable","outputs":[{"internalType":"uint256","name":"statBoost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getStatBoosted","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"getStats","outputs":[{"internalType":"uint256","name":"stamina","type":"uint256"},{"internalType":"uint256","name":"strength","type":"uint256"},{"internalType":"uint256","name":"speed","type":"uint256"},{"internalType":"uint256","name":"courage","type":"uint256"},{"internalType":"uint256","name":"intelligence","type":"uint256"},{"internalType":"uint256","name":"health","type":"uint256"},{"internalType":"uint256","name":"morale","type":"uint256"},{"internalType":"uint256","name":"experience","type":"uint256"},{"internalType":"uint256","name":"level","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"getWrappedTokenDetails","outputs":[{"internalType":"address","name":"collectionAddress","type":"address"},{"internalType":"uint256","name":"wrappedTokenID","type":"uint256"},{"internalType":"enum WrappedStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collectionAddress","type":"address"},{"internalType":"uint256","name":"wrappedTokenID","type":"uint256"}],"name":"hashWrappedToken","outputs":[{"internalType":"bytes32","name":"wrappedTokenHash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"statIndex","type":"uint256"}],"name":"increaseStat","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"isCitizen","outputs":[{"internalType":"bool","name":"citizen","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collectionAddress","type":"address"}],"name":"isCollectionEnabled","outputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"isMercenary","outputs":[{"internalType":"bool","name":"mercenary","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collectionAddress","type":"address"},{"internalType":"uint256","name":"wrappedTokenID","type":"uint256"}],"name":"isNeverWrapped","outputs":[{"internalType":"bool","name":"tokenNeverWrapped","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collectionAddress","type":"address"},{"internalType":"uint256","name":"wrappedTokenID","type":"uint256"}],"name":"isWrapped","outputs":[{"internalType":"bool","name":"tokenIsWrapped","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes16[]","name":"traits","type":"bytes16[]"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removeAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","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":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"uri","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"statIndex","type":"uint256"}],"name":"setStatTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"components":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint256","name":"numberOfActivities","type":"uint256"},{"internalType":"uint256","name":"activityDuration","type":"uint256"},{"internalType":"uint256","name":"startBlock","type":"uint256"},{"internalType":"uint256","name":"endBlock","type":"uint256"},{"internalType":"uint256","name":"completedBlock","type":"uint256"}],"internalType":"struct Activity","name":"activity","type":"tuple"}],"name":"startActivity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"stats","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"statsPerLevel","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","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":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenIDByHash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"unwrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"}],"name":"updateActivityStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newStatsPerLevel","type":"uint256"}],"name":"updateStatsPerLevel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"bytes16[]","name":"traits","type":"bytes16[]"}],"name":"updateTraits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"visualTraits","outputs":[{"internalType":"bytes16","name":"","type":"bytes16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"wrappedTokenID","type":"uint256"},{"internalType":"address","name":"collectionAddress","type":"address"}],"name":"wrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"wrappedToken","outputs":[{"internalType":"address","name":"collectionAddress","type":"address"},{"internalType":"uint256","name":"wrappedTokenID","type":"uint256"},{"internalType":"enum WrappedStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"wrappedTokenHashByID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]