// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol)pragmasolidity ^0.8.0;import"./IAccessControl.sol";
import"../utils/Context.sol";
import"../utils/Strings.sol";
import"../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/abstractcontractAccessControlisContext, IAccessControl, ERC165{
structRoleData {
mapping(address=>bool) members;
bytes32 adminRole;
}
mapping(bytes32=> RoleData) private _roles;
bytes32publicconstant DEFAULT_ADMIN_ROLE =0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/modifieronlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverridereturns (bool) {
return interfaceId ==type(IAccessControl).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/functionhasRole(bytes32 role, address account) publicviewvirtualoverridereturns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/function_checkRole(bytes32 role) internalviewvirtual{
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/function_checkRole(bytes32 role, address account) internalviewvirtual{
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/functiongetRoleAdmin(bytes32 role) publicviewvirtualoverridereturns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/functiongrantRole(bytes32 role, address account) publicvirtualoverrideonlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/functionrevokeRole(bytes32 role, address account) publicvirtualoverrideonlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/functionrenounceRole(bytes32 role, address account) publicvirtualoverride{
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/function_setupRole(bytes32 role, address account) internalvirtual{
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/function_setRoleAdmin(bytes32 role, bytes32 adminRole) internalvirtual{
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/function_grantRole(bytes32 role, address account) internalvirtual{
if (!hasRole(role, account)) {
_roles[role].members[account] =true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/function_revokeRole(bytes32 role, address account) internalvirtual{
if (hasRole(role, account)) {
_roles[role].members[account] =false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
Contract Source Code
File 2 of 25: Address.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)pragmasolidity ^0.8.1;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/functionisContract(address account) internalviewreturns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0// for contracts in construction, since the code is only stored at the end// of the constructor execution.return account.code.length>0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/functionsendValue(addresspayable 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");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(address(this).balance>= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytesmemory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytesmemory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytesmemory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/functionverifyCallResult(bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalpurereturns (bytesmemory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assembly/// @solidity memory-safe-assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
Contract Source Code
File 3 of 25: Base64.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol)pragmasolidity ^0.8.0;/**
* @dev Provides a set of functions to operate with Base64 strings.
*
* _Available since v4.5._
*/libraryBase64{
/**
* @dev Base64 Encoding/Decoding Table
*/stringinternalconstant _TABLE ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/functionencode(bytesmemory data) internalpurereturns (stringmemory) {
/**
* Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
* https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
*/if (data.length==0) return"";
// Loads the table into memorystringmemory table = _TABLE;
// Encoding takes 3 bytes chunks of binary data from `bytes` data parameter// and split into 4 numbers of 6 bits.// The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up// - `data.length + 2` -> Round up// - `/ 3` -> Number of 3-bytes chunks// - `4 *` -> 4 characters for each chunkstringmemory result =newstring(4* ((data.length+2) /3));
/// @solidity memory-safe-assemblyassembly {
// Prepare the lookup table (skip the first "length" byte)let tablePtr :=add(table, 1)
// Prepare result pointer, jump over lengthlet resultPtr :=add(result, 32)
// Run over the input, 3 bytes at a timefor {
let dataPtr := data
let endPtr :=add(data, mload(data))
} lt(dataPtr, endPtr) {
} {
// Advance 3 bytes
dataPtr :=add(dataPtr, 3)
let input :=mload(dataPtr)
// To write each character, shift the 3 bytes (18 bits) chunk// 4 times in blocks of 6 bits for each character (18, 12, 6, 0)// and apply logical AND with 0x3F which is the number of// the previous character in the ASCII table prior to the Base64 Table// The result is then added to the table to get the character to write,// and finally write it in the result pointer but with a left shift// of 256 (1 byte) - 8 (1 ASCII char) = 248 bitsmstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr :=add(resultPtr, 1) // Advancemstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr :=add(resultPtr, 1) // Advancemstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
resultPtr :=add(resultPtr, 1) // Advancemstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
resultPtr :=add(resultPtr, 1) // Advance
}
// When data `bytes` is not exactly 3 bytes long// it is padded with `=` characters at the endswitchmod(mload(data), 3)
case1 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}
Contract Source Code
File 4 of 25: CharacterActivity.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"./CharacterStats.sol";
contractCharacterActivityisCharacterStats{
// STATE VARIABLES/// @dev A mapping to track a characters activitymapping(uint256=> Activity) public charactersActivity;
// EVENTSeventActivityStatusUpdated(addressindexed account, uint256indexed tokenID, bool active);
eventActivityStarted(addressindexed account, uint256indexed tokenID, Activity activity);
// EXTERNAL FUNCTIONS/// @dev Update characters activity status/// @param tokenID Characters ID/// @param active the amountfunction_updateActivityStatus(uint256 tokenID, bool active)
internal{
// Write an event to the chainemit ActivityStatusUpdated(_msgSender(), tokenID, active);
// Set active
charactersActivity[tokenID].active = active;
if (!active) {
// Set block at which the activity completes
charactersActivity[tokenID].completedBlock =block.number;
}
}
/// @dev Update characters Activity Details/// @param tokenID Characters ID/// @param activity the activity details defined in the Activity structfunction_startActivity(uint256 tokenID, Activity calldata activity)
internal{
require(activity.endBlock > activity.startBlock, "End block should be higher than start");
// Write an event to the chainemit ActivityStarted(_msgSender(), tokenID, activity);
// Set the activity details
charactersActivity[tokenID] = activity;
}
//VIEWS/// @dev PUBLIC: Blocks remaining in activity, returns 0 if finished/// @param tokenID Characters IDfunctiongetBlocksUntilActivityEnds(uint256 tokenID)
externalviewreturns (uint256 blocksRemaining
)
{
// Shortcut to characters activity
Activity storage activity = charactersActivity[tokenID];
if (activity.endBlock >block.number) {
return activity.endBlock -block.number;
}
}
}
Contract Source Code
File 5 of 25: CharacterManager.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.8.0;import"@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import"./CollectionManager.sol";
contractCharacterManagerisCollectionManager{
// STATE VARIABLES/// @dev A permanent mapping to track the the underlying collection & token to a hash of the collection address & wrappedTokenID/// @dev Hash of (collection & wrappedTokenID) >> WrappedToken(collection, wrappedTokenID)mapping (bytes32=> WrappedToken) public wrappedToken;
/// @dev A mapping to track the wrapped token to the underlying collection & token/// @dev tokenID >> hash of the WrappedTokenmapping (uint256=>bytes32) public wrappedTokenHashByID;
/// @dev Maps the underlying token hash to the token id/// @dev Hash >> tokenID of the wrapped charactermapping (bytes32=>uint256) public tokenIDByHash;
// EVENTSeventWrapped(addressindexed account, addressindexed collection, uint256 blockNumber, uint256 wrappedTokenID, uint256 tokenID, bytes32 wrappedTokenHash);
eventUnwrapped(addressindexed account, addressindexed collection, uint256 blockNumber, uint256 wrappedTokenID, uint256 tokenID, bytes32 wrappedTokenHash);
// FUNCTIONS/// @dev PUBLIC: Add an NFT to the contract/// @param collectionAddress the address of the collection/// @param wrappedTokenID the id of the NFT to wrap/// @param tokenID Characters IDfunction_wrap(address account, address collectionAddress, uint256 wrappedTokenID, uint256 tokenID)
internalisRegistered(collectionAddress)
{
// Calculate the underlying token hashbytes32 wrappedTokenHash = hashWrappedToken(collectionAddress, wrappedTokenID);
// If this character has not been wrapped previously thenif (isNeverWrapped(collectionAddress, wrappedTokenID)) {
// Add Collection address to the mapping
wrappedToken[wrappedTokenHash].collectionAddress = collectionAddress;
// Add Underlying Token ID to the mapping
wrappedToken[wrappedTokenHash].wrappedTokenID = wrappedTokenID;
// Map the wrapped token id to underlying token hash
wrappedTokenHashByID[tokenID] = wrappedTokenHash;
// Map the underlying token hash to the wrapped token id
tokenIDByHash[wrappedTokenHash] = tokenID;
}
// Flag status as wrapped
wrappedToken[wrappedTokenHash].status = WrappedStatus.Wrapped;
// Write an eventemit Wrapped(account, collectionAddress, block.number, wrappedTokenID, tokenID, wrappedTokenHash);
// Transfer character to contract
IERC721(collectionAddress).safeTransferFrom(account, address(this), wrappedTokenID);
}
/// @dev PUBLIC: Release an NFT from the contract/// @dev Relies on the Owner check being completed when the wrapped token is burned/// @param tokenID the id of the NFT to releasefunction_unwrap(uint256 tokenID)
internal{
(address collectionAddress, uint256 wrappedTokenID, WrappedStatus status) = getWrappedTokenDetails(tokenID);
// Ensure token is wrappedrequire(status == WrappedStatus.Wrapped, "There is no token to unwrap");
// Calculate the underlying token hashbytes32 wrappedTokenHash = hashWrappedToken(collectionAddress, wrappedTokenID);
// Flag status as unwrapped
wrappedToken[wrappedTokenHash].status = WrappedStatus.Unwrapped;
// Write an eventemit Unwrapped(_msgSender(), collectionAddress, block.number, wrappedTokenID, tokenID, wrappedTokenHash);
// Return Item to owner
IERC721(collectionAddress).safeTransferFrom(address(this), _msgSender(), wrappedTokenID);
}
// VIEW FUNCTIONS/// @dev Check mapping for wrapped character underlying token details/// @param tokenID Characters IDfunctiongetWrappedTokenDetails(uint256 tokenID)
publicviewreturns (address collectionAddress,
uint256 wrappedTokenID,
WrappedStatus status
)
{
return (wrappedToken[wrappedTokenHashByID[tokenID]].collectionAddress,
wrappedToken[wrappedTokenHashByID[tokenID]].wrappedTokenID,
wrappedToken[wrappedTokenHashByID[tokenID]].status
);
}
/// @dev Check if a token is wrapped/// @param collectionAddress the address of the collection/// @param wrappedTokenID the id of the NFT to releasefunctionisWrapped(address collectionAddress, uint256 wrappedTokenID)
externalviewreturns (bool tokenIsWrapped
)
{
if (wrappedToken[hashWrappedToken(collectionAddress, wrappedTokenID)].status == WrappedStatus.Wrapped) {
return (true);
}
}
/// @dev Check if a token is wrapped/// @param collectionAddress the address of the collection/// @param wrappedTokenID the id of the NFT to releasefunctionisNeverWrapped(address collectionAddress, uint256 wrappedTokenID)
publicviewreturns (bool tokenNeverWrapped
)
{
if (wrappedToken[hashWrappedToken(collectionAddress, wrappedTokenID)].status == WrappedStatus.NeverWrapped) {
return (true);
}
}
/// @dev Hash the underlying collection details/// @param collectionAddress the address of the collection/// @param wrappedTokenID the id of the NFT to releasefunctionhashWrappedToken(address collectionAddress, uint256 wrappedTokenID)
publicpurereturns (bytes32 wrappedTokenHash
)
{
wrappedTokenHash =keccak256(abi.encodePacked(collectionAddress, wrappedTokenID));
}
}
Contract Source Code
File 6 of 25: CharacterStats.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.8.0;import"@openzeppelin/contracts/utils/math/SafeCast.sol";
import"../characters/interfaces/IFarmlandCollectible.sol";
import"./CharacterManager.sol";
contractCharacterStatsisCharacterManager{
usingSafeCastforuint256;
// STATE VARIABLES/// @dev Store the mapping for underlying characters to their statsmapping(bytes32=>uint16[]) public stats;
/// @dev Stores the total number of stats boosted by tokenIDmapping(uint256=>uint16) public getStatBoosted;
/// @dev Stores the additional stats available to boost for each additional leveluint16public statsPerLevel =3;
// EVENTSeventStatIncreased(addressindexed account, uint256 tokenID, uint256 amount, uint256 statIndex);
eventStatDecreased(addressindexed account, uint256 tokenID, uint256 amount, uint256 statIndex);
// EXTERNAL FUNCTIONS/// @dev Increases a stat/// @param tokenID ID of the token/// @param amount to increase/// @param statIndex index of statfunction_increaseStat(uint256 tokenID, uint256 amount, uint256 statIndex)
internal{
// Get the underlying token hashbytes32 wrappedTokenHash = wrappedTokenHashByID[tokenID];
// Get current statuint16 currentStat = stats[wrappedTokenHash][statIndex];
// Set standard max statuint16 maxStat =99;
if (statIndex ==5) {
// Health has a different calculation for max stat
maxStat = getMaxHealth(tokenID).toUint16();
} elseif (statIndex ==6) {
// Morale has a different calculation for max stat
maxStat = getMaxMorale(tokenID).toUint16();
} elseif (statIndex >6) {
// Experience has a higher max stat
maxStat =10000;
}
require(currentStat != maxStat, "Stat already at maximum");
// Check to see if we'll go above the max stat valueif (currentStat + amount.toUint16() < maxStat +1) {
// Increase stat
stats[wrappedTokenHash][statIndex] += amount.toUint16();
} else {
// Set to max for the stat
stats[wrappedTokenHash][statIndex] = maxStat;
}
// Write an event to the chainemit StatIncreased(_msgSender(), tokenID, amount, statIndex);
}
/// @dev Decreases a stat/// @param tokenID ID of the token/// @param amount to increase/// @param statIndex index of statfunction_decreaseStat(uint256 tokenID, uint256 amount, uint256 statIndex)
internal{
// Get the underlying token hashbytes32 wrappedTokenHash = wrappedTokenHashByID[tokenID];
// Get current statuint16 currentStat = stats[wrappedTokenHash][statIndex];
// Check to see if we'll go below the minimum stat of 1if (currentStat > amount.toUint16()) {
// Decrease stat
stats[wrappedTokenHash][statIndex] -= amount.toUint16();
} else {
// Otherwise set to minimum of 1
stats[wrappedTokenHash][statIndex] =1;
}
// Write an event to the chainemit StatDecreased(_msgSender(), tokenID, amount, statIndex);
}
/// @dev Set characters stat to an arbitrary amount/// @dev if amount = stat then there's no change/// @param tokenID Characters ID/// @param amount to addfunction_setStatTo(uint256 tokenID, uint256 amount, uint256 statIndex)
internal{
// Get the underlying token hashbytes32 wrappedTokenHash = wrappedTokenHashByID[tokenID];
// Get current statuint16 currentStat = stats[wrappedTokenHash][statIndex];
if (amount.toUint16() > currentStat) {
_increaseStat(tokenID, amount.toUint16() - currentStat, statIndex);
} else {
_decreaseStat(tokenID, currentStat - amount, statIndex);
}
}
/// @dev Boost stats based on level, enables character progression/// @param tokenID Characters ID/// @param amount amount to increase stat/// @param statIndex which stat to increasefunction_boostStat(uint256 tokenID, uint256 amount, uint256 statIndex)
internal{
// Ensure that only static stats can be increasedrequire(statIndex <5, "Invalid Stat");
// Ensure that the max stat boost won't be exceededrequire(amount <= getStatBoostAvailable(tokenID), "This will exceed the available boosts for this character");
// Increase the state variable tracking the boosts
getStatBoosted[tokenID] += amount.toUint16();
// Increase requested Stat
_increaseStat(tokenID, amount ,statIndex);
}
// INTERNAL FUNCTIONS/// @dev Import or generate character stats/// @param collectionAddress the address of the collection/// @param wrappedTokenID the id of the NFT to releasefunction_storeStats(address collectionAddress, uint256 wrappedTokenID)
internalisRegistered(collectionAddress)
{
uint256 stamina; uint256 strength; uint256 speed; uint256 courage; uint256 intelligence; uint256 health; uint256 morale;
// Calculate the underlying token hashbytes32 wrappedTokenHash = hashWrappedToken(collectionAddress, wrappedTokenID);
// Ensure the stats haven't previously been generatedrequire(stats[wrappedTokenHash].length==0, "Traits can be created once");
// If collection is nativeif (characterCollections[collectionAddress].native) {
// Get Native Character stats
(, stamina, strength, speed, courage, intelligence) = IFarmlandCollectible(collectionAddress).collectibleTraits(wrappedTokenID);
} else {
// Otherwise generate some random statsuint256 range = characterCollections[collectionAddress].range;
uint256 offset = characterCollections[collectionAddress].offset;
// Define array to store random numbersuint256[] memory randomNumbers =newuint256[](5);
randomNumbers = _getRandomNumbers(5, wrappedTokenID);
// Set stat values
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;
}
// Calculate health
health = (strength + stamina) /2;
// Give bonus for a Tank or Warriorif (strength >95|| stamina >95)
{
health += health /2;
}
// Calculate morale
morale = (courage + intelligence) /2 ;
// Give bonus for a Genius or Heroif (courage >95|| intelligence >95)
{
morale += morale /2;
}
// Assign the stats (experience & level start at 0)
stats[wrappedTokenHash] = [
stamina.toUint16(), // 0
strength.toUint16(), // 1
speed.toUint16(), // 2
courage.toUint16(), // 3
intelligence.toUint16(), // 4
health.toUint16(), // 5
morale.toUint16(), // 60]; // 7 - experience
}
/// @dev Returns an array of Random Numbers/// @param n number of random numbers to generate/// @param salt a number that adds to randomnessfunction_getRandomNumbers(uint256 n, uint256 salt)
internalviewreturns (uint256[] memory randomNumbers)
{
randomNumbers =newuint256[](n);
for (uint256 i =0; i < n;) {
randomNumbers[i] =uint256(keccak256(abi.encodePacked(block.timestamp, salt, i)));
unchecked { i++; }
}
}
// ADMIN FUNCTIONS/// @dev Update the base stats per levelfunctionupdateStatsPerLevel(uint256 newStatsPerLevel)
externalonlyOwner{
statsPerLevel = newStatsPerLevel.toUint16();
}
// VIEW FUNCTIONS/// @dev Returns the wrapped characters extended stats/// @param tokenID ID of the tokenfunctiongetStats(uint256 tokenID)
publicviewreturns (uint256 stamina, uint256 strength, uint256 speed, uint256 courage, uint256 intelligence, uint256 health, uint256 morale, uint256 experience, uint256 level
)
{
// Get the underlying token hashbytes32 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);
}
}
/// @dev Returns the wrapped characters level/// @param tokenID ID of the tokenfunctiongetLevel(uint256 tokenID)
publicviewreturns (uint256 level
)
{
// Get the underlying token hashbytes32 wrappedTokenHash = wrappedTokenHashByID[tokenID];
// Level is the square root of Experiencereturn sqrt(stats[wrappedTokenHash][7]);
}
/// @dev Returns the square root of a number/// @dev https://github.com/Uniswap/uniswap-v2-core/blob/4dd59067c76dea4a0e8e4bfdda41877a6b16dedc/contracts/libraries/Math.sol#L11-L22functionsqrt(uint256 y)
internalpurereturns (uint256 z
)
{
if (y >3) {
z = y;
uint x = y /2+1;
while (x < z) {
z = x;
x = (y / x + x) /2;
}
} elseif (y !=0) {
z =1;
}
}
/// @dev Returns a characters default max health/// @param tokenID Characters IDfunctiongetMaxHealth(uint256 tokenID)
publicviewreturns (uint256 health
)
{
// Retrieve stats
(uint256 stamina, uint256 strength,,,,,,,) = getStats(tokenID);
// Calculate the characters health
health = (strength + stamina) /2;
// Bonus for Tank or Warriorif (strength >95|| stamina >95)
{
health += health /2;
}
}
/// @dev Return a default max morale .. a combination of courage & intelligence/// @param tokenID Characters IDfunctiongetMaxMorale(uint256 tokenID)
publicviewreturns (uint256 morale
)
{
// Retrieve stats
(,,,uint256 courage, uint256 intelligence,,,,) = getStats(tokenID);
// Set Morale
morale = (courage + intelligence) /2 ;
// Bonus for Genius or Heroif (courage >95|| intelligence >95)
{
morale += morale /2;
}
}
/// @dev Return the stat boost available for a character/// @param tokenID Characters IDfunctiongetStatBoostAvailable(uint256 tokenID)
publicviewreturns (uint256 statBoost)
{
return (getLevel(tokenID) * statsPerLevel) - getStatBoosted[tokenID];
}
}
Contract Source Code
File 7 of 25: CollectionManager.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"./interfaces/IWrappedCharacters.sol";
import"../utils/Permissioned.sol";
contractCollectionManagerisPermissioned{
// CONSTRUCTORconstructor () Permissioned() {}
// STATE VARIABLES/// @dev Create an array to track the Character collectionsmapping(address=> Collection) public characterCollections;
// MODIFIERS/// @dev Check if the collection is wrappable/// @param collectionAddress address of collectionmodifierisRegistered(address collectionAddress) {
require(isCollectionEnabled(collectionAddress) || collectionAddress ==address(this),"This collection is not registered");
_;
}
/// @dev Check if the collection is wrappable/// @param collectionAddress address of collectionmodifierisWrappable(address collectionAddress) {
require(isCollectionEnabled(collectionAddress) && collectionAddress !=address(this),"This collection is not wrappable");
_;
}
// EVENTSeventCollectionEnabled(addressindexed account, address collectionAddress, bool native, uint256 range, uint256 offset);
eventCollectionDisabled(addressindexed account, address collectionAddress);
// FUNCTIONS/// @dev Enables a NFT collection to be wrapped/// @param collectionAddress address of the NFT collection/// @param native is this a native Farmland NFT collection/// @param range the max range for non native stats i.e, when added to the offset the range gives the maximum stat/// @param offset the offset for not native stats i.e., the floor for statsfunctionenableCollection(address collectionAddress, bool native, uint256 range, uint256 offset)
externalonlyOwner{
// Flag if collection is native to farmland
characterCollections[collectionAddress].native = native;
// Add range to the collection mapping
characterCollections[collectionAddress].range = range;
// Add offset to the collection mapping
characterCollections[collectionAddress].offset = offset;
emit CollectionEnabled(_msgSender(), collectionAddress, native, range, offset);
}
/// @dev Disables a NFT collection from being wrapped/// @param collectionAddress address of the NFT collectionfunctiondisableCollection(address collectionAddress)
externalonlyOwner{
// Delete the mappingdelete characterCollections[collectionAddress];
emit CollectionDisabled(_msgSender(), collectionAddress);
}
// VIEWS/// @dev Is a NFT collection enabled for wrapping/// @param collectionAddress address of the NFT collectionfunctionisCollectionEnabled(address collectionAddress)
publicviewreturns (bool enabled
)
{
if (characterCollections[collectionAddress].range >0) {
returntrue;
}
}
}
Contract Source Code
File 8 of 25: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)pragmasolidity ^0.8.0;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 9 of 25: ERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)pragmasolidity ^0.8.0;import"./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/abstractcontractERC165isIERC165{
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverridereturns (bool) {
return interfaceId ==type(IERC165).interfaceId;
}
}
Contract Source Code
File 10 of 25: ERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/ERC721.sol)pragmasolidity ^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";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/contractERC721isContext, ERC165, IERC721, IERC721Metadata{
usingAddressforaddress;
usingStringsforuint256;
// Token namestringprivate _name;
// Token symbolstringprivate _symbol;
// Mapping from token ID to owner addressmapping(uint256=>address) private _owners;
// Mapping owner address to token countmapping(address=>uint256) private _balances;
// Mapping from token ID to approved addressmapping(uint256=>address) private _tokenApprovals;
// Mapping from owner to operator approvalsmapping(address=>mapping(address=>bool)) private _operatorApprovals;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/constructor(stringmemory name_, stringmemory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride(ERC165, IERC165) returns (bool) {
return
interfaceId ==type(IERC721).interfaceId||
interfaceId ==type(IERC721Metadata).interfaceId||super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/functionbalanceOf(address owner) publicviewvirtualoverridereturns (uint256) {
require(owner !=address(0), "ERC721: address zero is not a valid owner");
return _balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/functionownerOf(uint256 tokenId) publicviewvirtualoverridereturns (address) {
address owner = _owners[tokenId];
require(owner !=address(0), "ERC721: invalid token ID");
return owner;
}
/**
* @dev See {IERC721Metadata-name}.
*/functionname() publicviewvirtualoverridereturns (stringmemory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/functionsymbol() publicviewvirtualoverridereturns (stringmemory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/functiontokenURI(uint256 tokenId) publicviewvirtualoverridereturns (stringmemory) {
_requireMinted(tokenId);
stringmemory baseURI = _baseURI();
returnbytes(baseURI).length>0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overridden in child contracts.
*/function_baseURI() internalviewvirtualreturns (stringmemory) {
return"";
}
/**
* @dev See {IERC721-approve}.
*/functionapprove(address to, uint256 tokenId) publicvirtualoverride{
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);
}
/**
* @dev See {IERC721-getApproved}.
*/functiongetApproved(uint256 tokenId) publicviewvirtualoverridereturns (address) {
_requireMinted(tokenId);
return _tokenApprovals[tokenId];
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/functionsetApprovalForAll(address operator, bool approved) publicvirtualoverride{
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/functionisApprovedForAll(address owner, address operator) publicviewvirtualoverridereturns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) publicvirtualoverride{
//solhint-disable-next-line max-line-lengthrequire(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner nor approved");
_transfer(from, to, tokenId);
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) publicvirtualoverride{
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytesmemory data
) publicvirtualoverride{
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner nor approved");
_safeTransfer(from, to, tokenId, data);
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* `data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/function_safeTransfer(addressfrom,
address to,
uint256 tokenId,
bytesmemory data
) internalvirtual{
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted (`_mint`),
* and stop existing when they are burned (`_burn`).
*/function_exists(uint256 tokenId) internalviewvirtualreturns (bool) {
return _owners[tokenId] !=address(0);
}
/**
* @dev Returns whether `spender` is allowed to manage `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/function_isApprovedOrOwner(address spender, uint256 tokenId) internalviewvirtualreturns (bool) {
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
}
/**
* @dev Safely mints `tokenId` and transfers it to `to`.
*
* Requirements:
*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/function_safeMint(address to, uint256 tokenId) internalvirtual{
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/function_safeMint(address to,
uint256 tokenId,
bytesmemory data
) internalvirtual{
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/function_mint(address to, uint256 tokenId) internalvirtual{
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);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/function_burn(uint256 tokenId) internalvirtual{
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
// Clear approvals
_approve(address(0), tokenId);
_balances[owner] -=1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
_afterTokenTransfer(owner, address(0), tokenId);
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/function_transfer(addressfrom,
address to,
uint256 tokenId
) internalvirtual{
require(ERC721.ownerOf(tokenId) ==from, "ERC721: transfer from incorrect owner");
require(to !=address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
// Clear approvals from the previous owner
_approve(address(0), tokenId);
_balances[from] -=1;
_balances[to] +=1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
_afterTokenTransfer(from, to, tokenId);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* Emits an {Approval} event.
*/function_approve(address to, uint256 tokenId) internalvirtual{
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*/function_setApprovalForAll(address owner,
address operator,
bool approved
) internalvirtual{
require(owner != operator, "ERC721: approve to caller");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Reverts if the `tokenId` has not been minted yet.
*/function_requireMinted(uint256 tokenId) internalviewvirtual{
require(_exists(tokenId), "ERC721: invalid token ID");
}
/**
* @dev Internal function to invoke {IERC721Receiver-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 bool whether the call correctly returned the expected magic value
*/function_checkOnERC721Received(addressfrom,
address to,
uint256 tokenId,
bytesmemory data
) privatereturns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytesmemory reason) {
if (reason.length==0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
/// @solidity memory-safe-assemblyassembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
returntrue;
}
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, ``from``'s `tokenId` will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/function_beforeTokenTransfer(addressfrom,
address to,
uint256 tokenId
) internalvirtual{}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/function_afterTokenTransfer(addressfrom,
address to,
uint256 tokenId
) internalvirtual{}
}
Contract Source Code
File 11 of 25: ERC721Holder.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC721/utils/ERC721Holder.sol)pragmasolidity ^0.8.0;import"../IERC721Receiver.sol";
/**
* @dev Implementation of the {IERC721Receiver} interface.
*
* Accepts all token transfers.
* Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
*/contractERC721HolderisIERC721Receiver{
/**
* @dev See {IERC721Receiver-onERC721Received}.
*
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/functiononERC721Received(address,
address,
uint256,
bytesmemory) publicvirtualoverridereturns (bytes4) {
returnthis.onERC721Received.selector;
}
}
Contract Source Code
File 12 of 25: IAccessControl.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)pragmasolidity ^0.8.0;/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/interfaceIAccessControl{
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/eventRoleAdminChanged(bytes32indexed role, bytes32indexed previousAdminRole, bytes32indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/eventRoleGranted(bytes32indexed role, addressindexed account, addressindexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/eventRoleRevoked(bytes32indexed role, addressindexed account, addressindexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/functionhasRole(bytes32 role, address account) externalviewreturns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/functiongetRoleAdmin(bytes32 role) externalviewreturns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/functiongrantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/functionrevokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/functionrenounceRole(bytes32 role, address account) external;
}
Contract Source Code
File 13 of 25: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 14 of 25: IERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/interfaceIERC721isIERC165{
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytescalldata data
) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/functionapprove(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/functionsetApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
}
Contract Source Code
File 15 of 25: IERC721Enumerable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)pragmasolidity ^0.8.0;import"../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/interfaceIERC721EnumerableisIERC721{
/**
* @dev Returns the total amount of tokens stored by the contract.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/functiontokenOfOwnerByIndex(address owner, uint256 index) externalviewreturns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/functiontokenByIndex(uint256 index) externalviewreturns (uint256);
}
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)pragmasolidity ^0.8.0;/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/interfaceIERC721Receiver{
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/functiononERC721Received(address operator,
addressfrom,
uint256 tokenId,
bytescalldata data
) externalreturns (bytes4);
}
Contract Source Code
File 18 of 25: IFarmlandCollectible.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import"@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
structCollectibleTraits {uint256 expiryDate; uint256 trait1; uint256 trait2; uint256 trait3; uint256 trait4; uint256 trait5;}
structCollectibleSlots {uint256 slot1; uint256 slot2; uint256 slot3; uint256 slot4; uint256 slot5; uint256 slot6; uint256 slot7; uint256 slot8;}
abstractcontractIFarmlandCollectibleisIERC721Enumerable, IERC721Metadata{
/// @dev Stores the key traits for Farmland Collectiblesmapping(uint256=> CollectibleTraits) public collectibleTraits;
/// @dev Stores slots for Farmland Collectibles, can be used to store various items / awards for collectiblesmapping(uint256=> CollectibleSlots) public collectibleSlots;
functionsetCollectibleSlot(uint256 id, uint256 slotIndex, uint256 slot) externalvirtual;
functionwalletOfOwner(address account) externalviewvirtualreturns(uint256[] memory tokenIds);
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"@openzeppelin/contracts/utils/Strings.sol";
import"@openzeppelin/contracts/utils/Base64.sol";
import"./WrappedCharacters.sol";
contractMercenariesisWrappedCharacters{
usingStringsforuint256;
constructor (stringmemory _initialBaseURI
)
WrappedCharacters("Farmland Mercenaries", "MERCENARIES") {
// Set the starting BaseURI
baseURI = _initialBaseURI;
}
// STATE VARIABLES/// @dev For tracking the mercenaries visual traitsmapping (uint256=>bytes16[]) public visualTraits;
// EVENTSeventMercenaryMinted(addressindexed account, uint256indexed tokenID, bytes16[] traits);
eventMercenaryTraitsUpdated(addressindexed account, uint256indexed tokenID, bytes16[] traits);
// FUNCTIONS/// @dev Allow an external contract to mint a mercenary/// @dev Enables giveaways to supportive community members/// @dev Enables external contracts with permission to mint mercenaries for promotions/// @param to recipient/// @param traits an array representing the mercenaries traits e.g., ["blue hat","brown eyes]functionmint(address to, bytes16[] calldata traits)
externalnonReentrantonlyAllowed{
// Increment wrapped token idunchecked { totalTokens++; }
// Store the totalTokens as a local variableuint256 tokenID = totalTokens;
// Write an eventemit MercenaryMinted(to, tokenID, traits);
// Set the stats
_storeStats(address(this),tokenID);
// Calculate the underlying token hashbytes32 wrappedTokenHash = hashWrappedToken(address(this), tokenID);
// Add Collection address to the mapping
wrappedToken[wrappedTokenHash].collectionAddress =address(this);
// Add Token ID to the mapping
wrappedToken[wrappedTokenHash].wrappedTokenID = tokenID;
// Map the underlying token hash to the wrapped token id
wrappedTokenHashByID[tokenID] = wrappedTokenHash;
// Add Visual Traits for mercenary
visualTraits[tokenID] = traits;
// Mint the Mercenaries
_mint(to, tokenID);
}
/// @dev Replace traits/// @param tokenID of mercenary/// @param traits an array representing the mercenaries traits e.g., [7,2,5,1,1]functionupdateTraits(uint256 tokenID, bytes16[] calldata traits)
externalnonReentrantonlyAllowedonlyExists(tokenID)
{
// Write an eventemit MercenaryTraitsUpdated(_msgSender(), tokenID, traits);
// Replace Visual Traits for mercenary
visualTraits[tokenID] = traits;
}
// VIEWS/// @dev Return the token onchain metadata/// @param tokenID Identifies the assetfunctiontokenURI(uint256 tokenID)
publicviewvirtualoverride(ERC721)
onlyExists(tokenID)
returns (stringmemory uri)
{
(address collectionAddress,uint256 wrappedTokenID,) = getWrappedTokenDetails(tokenID);
if (collectionAddress ==address(this)) {
bytes32 wrappedTokenHash = hashWrappedToken(collectionAddress, wrappedTokenID);
uint256 level = getLevel(tokenID);
stringmemory _url = ERC721.tokenURI(tokenID);
stringmemory url =string(abi.encodePacked(_url,".png"));
stringmemory mercenaryName =string(abi.encodePacked("Mercenary #",Strings.toString(tokenID)));
stringmemory 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), '" },'
));
stringmemory output = Base64.encode(abi.encodePacked(json1, encodeTraits(tokenID), encodeStats(wrappedTokenHash)));
returnstring(abi.encodePacked('data:application/json;base64,', output)); // Return the result
} else {
return IERC721Metadata(collectionAddress).tokenURI(wrappedTokenID);
}
}
functionencodeTraits(uint256 tokenID)
internalviewreturns (stringmemory)
{
bytes16[] memory traits = visualTraits[tokenID];
stringmemory 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]), '" },'
));
stringmemory 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]), '" },'
));
returnstring(abi.encodePacked(json1, json2)); // Return the result
}
functionencodeStats(bytes32 wrappedTokenHash)
internalviewreturns (stringmemory)
{
uint16[] memory stat = stats[wrappedTokenHash];
stringmemory 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]), '" },'
));
stringmemory 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]), '" }',
']',
'}'
));
returnstring(abi.encodePacked(json1, json2)); // Return the result
}
function_bytes16ToString(bytes16 toConvert)
privatepurereturns (stringmemory)
{
uint8 i =0;
while(i <16&& toConvert[i] !=0) {
unchecked { i++; }
}
bytesmemory bytesArray =newbytes(i);
for (i =0; i <16&& toConvert[i] !=0;) {
bytesArray[i] = toConvert[i];
unchecked { i++; }
}
returnstring(bytesArray);
}
function_baseURI()
internalviewoverride(ERC721)
returns (stringmemory)
{
return baseURI;
}
/// @dev Check if token is a mercenary/// @param tokenID Identifies the assetfunctionisMercenary(uint256 tokenID)
externalviewonlyExists(tokenID)
returns (bool mercenary)
{
(address collectionAddress,,) = getWrappedTokenDetails(tokenID);
if (collectionAddress ==address(this)) {returntrue;}
}
/// @dev Check if mercenary is a wrapped citizen/// @param tokenID Identifies the assetfunctionisCitizen(uint256 tokenID)
externalviewonlyExists(tokenID)
returns (bool citizen)
{
(address collectionAddress,,) = getWrappedTokenDetails(tokenID);
if (characterCollections[collectionAddress].native && collectionAddress !=address(this)) {returntrue;}
}
/// @dev The following functions are overrides required by Solidity.function_beforeTokenTransfer(addressfrom, address to, uint256 tokenId)
internaloverride(ERC721)
{
super._beforeTokenTransfer(from, to, tokenId);
// Revert if the mercenary is activerequire(!charactersActivity[tokenId].active, "Mercenary is active");
}
}
Contract Source Code
File 21 of 25: Permissioned.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"@openzeppelin/contracts/access/AccessControl.sol";
contractPermissionedisAccessControl{
constructor () {
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
// STATE VARIABLES/// @dev Defines the accessible rolesbytes32publicconstant ACCESS_ROLE =keccak256("ACCESS_ROLE");
// MODIFIERS/// @dev Only allows admin accountsmodifieronlyOwner() {
require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Caller is not the owner");
_; // Call the actual code
}
/// @dev Only allows accounts with permissionmodifieronlyAllowed() {
require(hasRole(ACCESS_ROLE, _msgSender()), "Caller does not have permission");
_; // Call the actual code
}
// FUNCTIONS/// @dev Add an account to the access role. Restricted to admins.functionaddAllowed(address account)
externalvirtualonlyOwner{
grantRole(ACCESS_ROLE, account);
}
/// @dev Add an account to the admin role. Restricted to admins.functionaddOwner(address account)
publicvirtualonlyOwner{
grantRole(DEFAULT_ADMIN_ROLE, account);
}
/// @dev Remove an account from the access role. Restricted to admins.functionremoveAllowed(address account)
externalvirtualonlyOwner{
revokeRole(ACCESS_ROLE, account);
}
///@dev Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.functiontransferOwnership(address newOwner)
externalvirtualonlyOwner{
require(newOwner !=address(0), "Permissioned: new owner is the zero address");
addOwner(newOwner);
renounceOwner();
}
/// @dev Remove oneself from the owner role.functionrenounceOwner()
publicvirtual{
renounceRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
// VIEWS/// @dev Return `true` if the account belongs to the admin role.functionisOwner(address account)
externalvirtualviewreturns (bool)
{
return hasRole(DEFAULT_ADMIN_ROLE, account);
}
/// @dev Return `true` if the account belongs to the access role.functionisAllowed(address account)
externalvirtualviewreturns (bool)
{
return hasRole(ACCESS_ROLE, account);
}
}
Contract Source Code
File 22 of 25: ReentrancyGuard.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)pragmasolidity ^0.8.0;/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/abstractcontractReentrancyGuard{
// Booleans are more expensive than uint256 or any type that takes up a full// word because each write operation emits an extra SLOAD to first read the// slot's contents, replace the bits taken up by the boolean, and then write// back. This is the compiler's defense against contract upgrades and// pointer aliasing, and it cannot be disabled.// The values being non-zero value makes deployment a bit more expensive,// but in exchange the refund on every call to nonReentrant will be lower in// amount. Since refunds are capped to a percentage of the total// transaction's gas, it is best to keep them low in cases like this one, to// increase the likelihood of the full refund coming into effect.uint256privateconstant _NOT_ENTERED =1;
uint256privateconstant _ENTERED =2;
uint256private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/modifiernonReentrant() {
// On the first call to nonReentrant, _notEntered will be truerequire(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
Contract Source Code
File 23 of 25: SafeCast.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/SafeCast.sol)pragmasolidity ^0.8.0;/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/librarySafeCast{
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/functiontoUint248(uint256 value) internalpurereturns (uint248) {
require(value <=type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
returnuint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/functiontoUint240(uint256 value) internalpurereturns (uint240) {
require(value <=type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
returnuint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/functiontoUint232(uint256 value) internalpurereturns (uint232) {
require(value <=type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
returnuint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/functiontoUint224(uint256 value) internalpurereturns (uint224) {
require(value <=type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
returnuint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/functiontoUint216(uint256 value) internalpurereturns (uint216) {
require(value <=type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
returnuint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/functiontoUint208(uint256 value) internalpurereturns (uint208) {
require(value <=type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
returnuint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/functiontoUint200(uint256 value) internalpurereturns (uint200) {
require(value <=type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
returnuint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/functiontoUint192(uint256 value) internalpurereturns (uint192) {
require(value <=type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
returnuint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/functiontoUint184(uint256 value) internalpurereturns (uint184) {
require(value <=type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
returnuint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/functiontoUint176(uint256 value) internalpurereturns (uint176) {
require(value <=type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
returnuint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/functiontoUint168(uint256 value) internalpurereturns (uint168) {
require(value <=type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
returnuint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/functiontoUint160(uint256 value) internalpurereturns (uint160) {
require(value <=type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
returnuint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/functiontoUint152(uint256 value) internalpurereturns (uint152) {
require(value <=type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
returnuint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/functiontoUint144(uint256 value) internalpurereturns (uint144) {
require(value <=type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
returnuint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/functiontoUint136(uint256 value) internalpurereturns (uint136) {
require(value <=type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
returnuint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/functiontoUint128(uint256 value) internalpurereturns (uint128) {
require(value <=type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
returnuint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/functiontoUint120(uint256 value) internalpurereturns (uint120) {
require(value <=type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
returnuint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/functiontoUint112(uint256 value) internalpurereturns (uint112) {
require(value <=type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
returnuint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/functiontoUint104(uint256 value) internalpurereturns (uint104) {
require(value <=type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
returnuint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/functiontoUint96(uint256 value) internalpurereturns (uint96) {
require(value <=type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
returnuint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/functiontoUint88(uint256 value) internalpurereturns (uint88) {
require(value <=type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
returnuint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/functiontoUint80(uint256 value) internalpurereturns (uint80) {
require(value <=type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
returnuint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/functiontoUint72(uint256 value) internalpurereturns (uint72) {
require(value <=type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
returnuint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/functiontoUint64(uint256 value) internalpurereturns (uint64) {
require(value <=type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
returnuint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/functiontoUint56(uint256 value) internalpurereturns (uint56) {
require(value <=type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
returnuint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/functiontoUint48(uint256 value) internalpurereturns (uint48) {
require(value <=type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
returnuint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/functiontoUint40(uint256 value) internalpurereturns (uint40) {
require(value <=type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
returnuint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/functiontoUint32(uint256 value) internalpurereturns (uint32) {
require(value <=type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
returnuint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/functiontoUint24(uint256 value) internalpurereturns (uint24) {
require(value <=type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
returnuint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/functiontoUint16(uint256 value) internalpurereturns (uint16) {
require(value <=type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
returnuint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/functiontoUint8(uint256 value) internalpurereturns (uint8) {
require(value <=type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
returnuint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/functiontoUint256(int256 value) internalpurereturns (uint256) {
require(value >=0, "SafeCast: value must be positive");
returnuint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/functiontoInt248(int256 value) internalpurereturns (int248) {
require(value >=type(int248).min&& value <=type(int248).max, "SafeCast: value doesn't fit in 248 bits");
returnint248(value);
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/functiontoInt240(int256 value) internalpurereturns (int240) {
require(value >=type(int240).min&& value <=type(int240).max, "SafeCast: value doesn't fit in 240 bits");
returnint240(value);
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/functiontoInt232(int256 value) internalpurereturns (int232) {
require(value >=type(int232).min&& value <=type(int232).max, "SafeCast: value doesn't fit in 232 bits");
returnint232(value);
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/functiontoInt224(int256 value) internalpurereturns (int224) {
require(value >=type(int224).min&& value <=type(int224).max, "SafeCast: value doesn't fit in 224 bits");
returnint224(value);
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/functiontoInt216(int256 value) internalpurereturns (int216) {
require(value >=type(int216).min&& value <=type(int216).max, "SafeCast: value doesn't fit in 216 bits");
returnint216(value);
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/functiontoInt208(int256 value) internalpurereturns (int208) {
require(value >=type(int208).min&& value <=type(int208).max, "SafeCast: value doesn't fit in 208 bits");
returnint208(value);
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/functiontoInt200(int256 value) internalpurereturns (int200) {
require(value >=type(int200).min&& value <=type(int200).max, "SafeCast: value doesn't fit in 200 bits");
returnint200(value);
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/functiontoInt192(int256 value) internalpurereturns (int192) {
require(value >=type(int192).min&& value <=type(int192).max, "SafeCast: value doesn't fit in 192 bits");
returnint192(value);
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/functiontoInt184(int256 value) internalpurereturns (int184) {
require(value >=type(int184).min&& value <=type(int184).max, "SafeCast: value doesn't fit in 184 bits");
returnint184(value);
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/functiontoInt176(int256 value) internalpurereturns (int176) {
require(value >=type(int176).min&& value <=type(int176).max, "SafeCast: value doesn't fit in 176 bits");
returnint176(value);
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/functiontoInt168(int256 value) internalpurereturns (int168) {
require(value >=type(int168).min&& value <=type(int168).max, "SafeCast: value doesn't fit in 168 bits");
returnint168(value);
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/functiontoInt160(int256 value) internalpurereturns (int160) {
require(value >=type(int160).min&& value <=type(int160).max, "SafeCast: value doesn't fit in 160 bits");
returnint160(value);
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/functiontoInt152(int256 value) internalpurereturns (int152) {
require(value >=type(int152).min&& value <=type(int152).max, "SafeCast: value doesn't fit in 152 bits");
returnint152(value);
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/functiontoInt144(int256 value) internalpurereturns (int144) {
require(value >=type(int144).min&& value <=type(int144).max, "SafeCast: value doesn't fit in 144 bits");
returnint144(value);
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/functiontoInt136(int256 value) internalpurereturns (int136) {
require(value >=type(int136).min&& value <=type(int136).max, "SafeCast: value doesn't fit in 136 bits");
returnint136(value);
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/functiontoInt128(int256 value) internalpurereturns (int128) {
require(value >=type(int128).min&& value <=type(int128).max, "SafeCast: value doesn't fit in 128 bits");
returnint128(value);
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/functiontoInt120(int256 value) internalpurereturns (int120) {
require(value >=type(int120).min&& value <=type(int120).max, "SafeCast: value doesn't fit in 120 bits");
returnint120(value);
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/functiontoInt112(int256 value) internalpurereturns (int112) {
require(value >=type(int112).min&& value <=type(int112).max, "SafeCast: value doesn't fit in 112 bits");
returnint112(value);
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/functiontoInt104(int256 value) internalpurereturns (int104) {
require(value >=type(int104).min&& value <=type(int104).max, "SafeCast: value doesn't fit in 104 bits");
returnint104(value);
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/functiontoInt96(int256 value) internalpurereturns (int96) {
require(value >=type(int96).min&& value <=type(int96).max, "SafeCast: value doesn't fit in 96 bits");
returnint96(value);
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/functiontoInt88(int256 value) internalpurereturns (int88) {
require(value >=type(int88).min&& value <=type(int88).max, "SafeCast: value doesn't fit in 88 bits");
returnint88(value);
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/functiontoInt80(int256 value) internalpurereturns (int80) {
require(value >=type(int80).min&& value <=type(int80).max, "SafeCast: value doesn't fit in 80 bits");
returnint80(value);
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/functiontoInt72(int256 value) internalpurereturns (int72) {
require(value >=type(int72).min&& value <=type(int72).max, "SafeCast: value doesn't fit in 72 bits");
returnint72(value);
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/functiontoInt64(int256 value) internalpurereturns (int64) {
require(value >=type(int64).min&& value <=type(int64).max, "SafeCast: value doesn't fit in 64 bits");
returnint64(value);
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/functiontoInt56(int256 value) internalpurereturns (int56) {
require(value >=type(int56).min&& value <=type(int56).max, "SafeCast: value doesn't fit in 56 bits");
returnint56(value);
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/functiontoInt48(int256 value) internalpurereturns (int48) {
require(value >=type(int48).min&& value <=type(int48).max, "SafeCast: value doesn't fit in 48 bits");
returnint48(value);
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/functiontoInt40(int256 value) internalpurereturns (int40) {
require(value >=type(int40).min&& value <=type(int40).max, "SafeCast: value doesn't fit in 40 bits");
returnint40(value);
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/functiontoInt32(int256 value) internalpurereturns (int32) {
require(value >=type(int32).min&& value <=type(int32).max, "SafeCast: value doesn't fit in 32 bits");
returnint32(value);
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/functiontoInt24(int256 value) internalpurereturns (int24) {
require(value >=type(int24).min&& value <=type(int24).max, "SafeCast: value doesn't fit in 24 bits");
returnint24(value);
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/functiontoInt16(int256 value) internalpurereturns (int16) {
require(value >=type(int16).min&& value <=type(int16).max, "SafeCast: value doesn't fit in 16 bits");
returnint16(value);
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/functiontoInt8(int256 value) internalpurereturns (int8) {
require(value >=type(int8).min&& value <=type(int8).max, "SafeCast: value doesn't fit in 8 bits");
returnint8(value);
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/functiontoInt256(uint256 value) internalpurereturns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positiverequire(value <=uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
returnint256(value);
}
}
Contract Source Code
File 24 of 25: Strings.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)pragmasolidity ^0.8.0;/**
* @dev String operations.
*/libraryStrings{
bytes16privateconstant _HEX_SYMBOLS ="0123456789abcdef";
uint8privateconstant _ADDRESS_LENGTH =20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/functiontoString(uint256 value) internalpurereturns (stringmemory) {
// Inspired by OraclizeAPI's implementation - MIT licence// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.solif (value ==0) {
return"0";
}
uint256 temp = value;
uint256 digits;
while (temp !=0) {
digits++;
temp /=10;
}
bytesmemory buffer =newbytes(digits);
while (value !=0) {
digits -=1;
buffer[digits] =bytes1(uint8(48+uint256(value %10)));
value /=10;
}
returnstring(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/functiontoHexString(uint256 value) internalpurereturns (stringmemory) {
if (value ==0) {
return"0x00";
}
uint256 temp = value;
uint256 length =0;
while (temp !=0) {
length++;
temp >>=8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/functiontoHexString(uint256 value, uint256 length) internalpurereturns (stringmemory) {
bytesmemory buffer =newbytes(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");
returnstring(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/functiontoHexString(address addr) internalpurereturns (stringmemory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
Contract Source Code
File 25 of 25: WrappedCharacters.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import"@openzeppelin/contracts/token/ERC721/ERC721.sol";
import"@openzeppelin/contracts/security/ReentrancyGuard.sol";
import"./CharacterActivity.sol";
contractWrappedCharactersisCharacterActivity, ERC721, ERC721Holder, ReentrancyGuard{
// CONSTRUCTORconstructor (stringmemory name_, stringmemory symbol_) ERC721(name_, symbol_) {}
// STATE VARIABLES// @dev Track the wrapped token iduint256internal totalTokens;
/// @dev This stores the base URI used to generate the token IDstringpublic baseURI;
// MODIFIERS/// @dev Only if a character is wrapped/// @param tokenID of charactermodifieronlyExists(uint256 tokenID) {
require (_exists(tokenID),"Character does not exist");
_;
}
/// @dev Only the owner of the character can perform this action/// @param tokenID of charactermodifieronlyOwnerOfToken(uint256 tokenID) {
require (ownerOf(tokenID) == _msgSender(),"Only the owner of the token can perform this action");
_;
}
// FUNCTIONS/// @dev Wraps an NFT & mints a wrappedCharacter/// @param account to interact with/// @param wrappedTokenID ID of the token/// @param collectionAddress address of the NFT collectionfunctionwrap(address account, uint256 wrappedTokenID, address collectionAddress)
externalnonReentrantisWrappable(collectionAddress)
onlyAllowed{
// Get the tokenID, if never wrapped before then it will be 0 & stamina will be 0uint256 tokenID;
if (isNeverWrapped(collectionAddress, wrappedTokenID)) {
// Increment wrapped token idunchecked { totalTokens++; }
// Store the totalTokens as a local variable
tokenID = totalTokens;
// Set the stats
_storeStats(collectionAddress, wrappedTokenID);
} else {
// Get the ID of previously wrapped token
tokenID = tokenIDByHash[hashWrappedToken(collectionAddress,wrappedTokenID)];
}
// Wrap the character
_wrap(account, collectionAddress, wrappedTokenID, tokenID);
// Mint a wrapped character
_mint(account, tokenID);
}
/// @dev Unwraps an NFT & burns the wrappedCharacter/// @param tokenID ID of the tokenfunctionunwrap(uint256 tokenID)
externalnonReentrantonlyExists(tokenID)
onlyOwnerOfToken(tokenID)
{
_burn(tokenID);
_unwrap(tokenID);
}
/// @dev Increases a stat/// @param tokenID ID of the token/// @param amount to increase/// @param statIndex index of statfunctionincreaseStat(uint256 tokenID, uint256 amount, uint256 statIndex)
externalonlyAllowedonlyExists(tokenID)
{
_increaseStat(tokenID, amount, statIndex);
}
/// @dev Decreases a stat/// @param tokenID ID of the token/// @param amount to increase/// @param statIndex index of statfunctiondecreaseStat(uint256 tokenID, uint256 amount, uint256 statIndex)
externalonlyAllowedonlyExists(tokenID)
{
_decreaseStat(tokenID, amount, statIndex);
}
/// @dev Set characters stat to an arbitrary amount/// @dev if amount = stat then there's no change/// @param tokenID Characters ID/// @param amount to addfunctionsetStatTo(uint256 tokenID, uint256 amount, uint256 statIndex)
externalonlyAllowedonlyExists(tokenID)
{
_setStatTo(tokenID, amount, statIndex);
}
/// @dev Boost stats based on level, enables character progression/// @param tokenID Characters ID/// @param amount amount to increase stat/// @param statIndex which stat to increasefunctionboostStat(uint256 tokenID, uint256 amount, uint256 statIndex)
externalonlyAllowedonlyExists(tokenID)
{
_boostStat(tokenID, amount, statIndex);
}
/// @dev Update characters activity status/// @param tokenID Characters ID/// @param active the amountfunctionupdateActivityStatus(uint256 tokenID, bool active)
externalonlyAllowedonlyExists(tokenID)
{
_updateActivityStatus (tokenID, active);
}
/// @dev Update characters Activity details/// @param tokenID Characters ID/// @param activity the activity details defined in the Activity structfunctionstartActivity(uint256 tokenID, Activity calldata activity)
externalonlyAllowedonlyExists(tokenID)
{
_startActivity(tokenID, activity);
}
// OWNER FUNCTION/// @dev If the metadata needs to be movedfunctionsetBaseURI(stringmemory uri)
externalonlyOwner{
baseURI = uri;
}
// VIEWS/// @dev Returns the total amount of tokens stored by the contract.functiontotalSupply() externalviewreturns (uint256)
{
return totalTokens;
}
functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverride (ERC721, AccessControl) returns (bool) {
returnsuper.supportsInterface(interfaceId);
}
}