// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.1;
/// @author thirdweb, OpenZeppelin Contracts (v4.9.0)
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @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
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [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.
* ====
*/
function isContract(address account) internal view returns (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://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @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._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "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._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
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._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @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._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
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._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
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._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Router, IRouter } from "../core/Router.sol";
import { IRouterState } from "../interface/IRouterState.sol";
import { IRouterStateGetters } from "../interface/IRouterStateGetters.sol";
import { BaseRouterStorage } from "../lib/BaseRouterStorage.sol";
import { ExtensionManager } from "./ExtensionManager.sol";
import { StringSet } from "../lib/StringSet.sol";
import "lib/sstore2/contracts/SSTORE2.sol";
/// @title BaseRouter
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice A router with an API to manage its extensions.
abstract contract BaseRouter is Router, ExtensionManager {
using StringSet for StringSet.Set;
/// @notice The address where the router's default extension set is stored.
address public immutable defaultExtensions;
/// @notice Initialize the Router with a set of default extensions.
constructor(Extension[] memory _extensions) {
address pointer;
if(_extensions.length > 0) {
_validateExtensions(_extensions);
pointer = SSTORE2.write(abi.encode(_extensions));
}
defaultExtensions = pointer;
}
/// @notice Initialize the Router with a set of default extensions.
function __BaseRouter_init() internal {
if(defaultExtensions == address(0)) {
return;
}
bytes memory data = SSTORE2.read(defaultExtensions);
Extension[] memory defaults = abi.decode(data, (Extension[]));
// Unchecked since we already validated extensions in constructor.
__BaseRouter_init_unchecked(defaults);
}
/// @notice Initializes the Router with a set of extensions.
function __BaseRouter_init_checked(Extension[] memory _extensions) internal {
_validateExtensions(_extensions);
__BaseRouter_init_unchecked(_extensions);
}
/// @notice Initializes the Router with a set of extensions.
function __BaseRouter_init_unchecked(Extension[] memory _extensions) internal {
for(uint256 i = 0; i < _extensions.length; i += 1) {
Extension memory extension = _extensions[i];
// Store: new extension name.
_extensionManagerStorage().extensionNames.add(extension.metadata.name);
// 1. Store: metadata for extension.
_setMetadataForExtension(extension.metadata.name, extension.metadata);
uint256 len = extension.functions.length;
for (uint256 j = 0; j < len; j += 1) {
// 2. Store: name -> extension.functions map
_extensionManagerStorage().extensions[extension.metadata.name].functions.push(extension.functions[j]);
// 3. Store: metadata for function.
_setMetadataForFunction(extension.functions[j].functionSelector, extension.metadata);
}
emit ExtensionAdded(extension.metadata.name, extension.metadata.implementation, extension);
}
}
/// @notice Returns the implementation contract address for a given function signature.
function getImplementationForFunction(bytes4 _functionSelector) public view virtual override returns (address) {
return getMetadataForFunction(_functionSelector).implementation;
}
/// @dev Validates default extensions.
function _validateExtensions(Extension[] memory _extensions) internal {
uint256 len = _extensions.length;
bool isValid = true;
for (uint256 i = 0; i < len; i += 1) {
isValid = _isValidExtension(_extensions[i]);
if(!isValid) {
break;
}
}
require(isValid, "BaseRouter: invalid extension.");
}
function _isValidExtension(Extension memory _extension) internal returns (bool isValid) {
isValid = bytes(_extension.metadata.name).length > 0 // non-empty name
&& !BaseRouterStorage.data().extensionMap[_extension.metadata.name] // unused name
&& _extension.metadata.implementation != address(0); // non-empty implementation
BaseRouterStorage.data().extensionMap[_extension.metadata.name] = true;
if(!isValid) {
return false;
}
uint256 len = _extension.functions.length;
for(uint256 i = 0; i < len; i += 1) {
if(!isValid) {
break;
}
ExtensionFunction memory _extFunction = _extension.functions[i];
/**
* Note: `bytes4(0)` is the function selector for the `receive` function.
* So, we maintain a special fn selector-signature mismatch check for the `receive` function.
**/
bool mismatch = false;
if(_extFunction.functionSelector == bytes4(0)) {
mismatch = keccak256(abi.encode(_extFunction.functionSignature)) != keccak256(abi.encode("receive()"));
} else {
mismatch = _extFunction.functionSelector !=
bytes4(keccak256(abi.encodePacked(_extFunction.functionSignature)));
}
// No fn signature-selector mismatch and no duplicate function.
isValid = !mismatch && !BaseRouterStorage.data().functionMap[_extFunction.functionSelector];
BaseRouterStorage.data().functionMap[_extFunction.functionSelector] = true;
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title BaseRouterStorage
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Defined storage for base router
library BaseRouterStorage {
/// @custom:storage-location erc7201:base.router.storage
bytes32 public constant BASE_ROUTER_STORAGE_POSITION = keccak256(abi.encode(uint256(keccak256("base.router.storage")) - 1));
struct Data {
/// @dev Mapping used only for checking default extension validity in constructor.
mapping(bytes4 => bool) functionMap;
/// @dev Mapping used only for checking default extension validity in constructor.
mapping(string => bool) extensionMap;
}
/// @dev Returns access to base router storage.
function data() internal pure returns (Data storage data_) {
bytes32 position = BASE_ROUTER_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library Bytecode {
error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end);
/**
@notice Generate a creation code that results on a contract with `_code` as bytecode
@param _code The returning value of the resulting `creationCode`
@return creationCode (constructor) for new contract
*/
function creationCodeFor(bytes memory _code) internal pure returns (bytes memory) {
/*
0x00 0x63 0x63XXXXXX PUSH4 _code.length size
0x01 0x80 0x80 DUP1 size size
0x02 0x60 0x600e PUSH1 14 14 size size
0x03 0x60 0x6000 PUSH1 00 0 14 size size
0x04 0x39 0x39 CODECOPY size
0x05 0x60 0x6000 PUSH1 00 0 size
0x06 0xf3 0xf3 RETURN
<CODE>
*/
return abi.encodePacked(
hex"63",
uint32(_code.length),
hex"80_60_0E_60_00_39_60_00_F3",
_code
);
}
/**
@notice Returns the size of the code on a given address
@param _addr Address that may or may not contain code
@return size of the code on the given `_addr`
*/
function codeSize(address _addr) internal view returns (uint256 size) {
assembly { size := extcodesize(_addr) }
}
/**
@notice Returns the code of a given address
@dev It will fail if `_end < _start`
@param _addr Address that may or may not contain code
@param _start number of bytes of code to skip on read
@param _end index before which to end extraction
@return oCode read from `_addr` deployed bytecode
Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd
*/
function codeAt(address _addr, uint256 _start, uint256 _end) internal view returns (bytes memory oCode) {
uint256 csize = codeSize(_addr);
if (csize == 0) return bytes("");
if (_start > csize) return bytes("");
if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end);
unchecked {
uint256 reqSize = _end - _start;
uint256 maxSize = csize - _start;
uint256 size = maxSize < reqSize ? maxSize : reqSize;
assembly {
// allocate output byte array - this could also be done without assembly
// by using o_code = new bytes(size)
oCode := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f))))
// store length in memory
mstore(oCode, size)
// actually retrieve the code, this needs assembly
extcodecopy(_addr, add(oCode, 0x20), _start, size)
}
}
}
}
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
import "../interface/IERC2771Context.sol";
import "./Initializable.sol";
/**
* @dev Context variant with ERC2771 support.
*/
library ERC2771ContextStorage {
/// @custom:storage-location erc7201:erc2771.context.storage
/// @dev keccak256(abi.encode(uint256(keccak256("erc2771.context.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 public constant ERC2771_CONTEXT_STORAGE_POSITION =
0x82aadcdf5bea62fd30615b6c0754b644e71b6c1e8c55b71bb927ad005b504f00;
struct Data {
mapping(address => bool) trustedForwarder;
}
function data() internal pure returns (Data storage data_) {
bytes32 position = ERC2771_CONTEXT_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
/**
* @dev Context variant with ERC2771 support.
*/
abstract contract ERC2771ContextUpgradeable is Initializable {
function __ERC2771Context_init(address[] memory trustedForwarder) internal onlyInitializing {
__ERC2771Context_init_unchained(trustedForwarder);
}
function __ERC2771Context_init_unchained(address[] memory trustedForwarder) internal onlyInitializing {
for (uint256 i = 0; i < trustedForwarder.length; i++) {
_erc2771ContextStorage().trustedForwarder[trustedForwarder[i]] = true;
}
}
function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
return _erc2771ContextStorage().trustedForwarder[forwarder];
}
function _msgSender() internal view virtual returns (address sender) {
if (isTrustedForwarder(msg.sender)) {
// The assembly code is more direct than the Solidity version using `abi.decode`.
assembly {
sender := shr(96, calldataload(sub(calldatasize(), 20)))
}
} else {
return msg.sender;
}
}
function _msgData() internal view virtual returns (bytes calldata) {
if (isTrustedForwarder(msg.sender)) {
return msg.data[:msg.data.length - 20];
} else {
return msg.data;
}
}
/// @dev Returns the ERC2771ContextStorage storage.
function _erc2771ContextStorage() internal pure returns (ERC2771ContextStorage.Data storage data) {
data = ERC2771ContextStorage.data();
}
uint256[49] private __gap;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../interface/IExtensionManager.sol";
import "../interface/IRouterState.sol";
import "../interface/IRouterStateGetters.sol";
import "../lib/ExtensionManagerStorage.sol";
/// @title ExtensionManager
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Defined storage and API for managing a router's extensions.
abstract contract ExtensionManager is IExtensionManager, IRouterState, IRouterStateGetters {
using StringSet for StringSet.Set;
/*///////////////////////////////////////////////////////////////
Modifier
//////////////////////////////////////////////////////////////*/
/// @notice Checks that a call to any external function is authorized.
modifier onlyAuthorizedCall() {
require(_isAuthorizedCallToUpgrade(), "ExtensionManager: unauthorized.");
_;
}
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns all extensions of the Router.
* @return allExtensions An array of all extensions.
*/
function getAllExtensions() external view virtual override returns (Extension[] memory allExtensions) {
string[] memory names = _extensionManagerStorage().extensionNames.values();
uint256 len = names.length;
allExtensions = new Extension[](len);
for (uint256 i = 0; i < len; i += 1) {
allExtensions[i] = _getExtension(names[i]);
}
}
/**
* @notice Returns the extension metadata for a given function.
* @param functionSelector The function selector to get the extension metadata for.
* @return metadata The extension metadata for a given function.
*/
function getMetadataForFunction(bytes4 functionSelector) public view virtual returns (ExtensionMetadata memory) {
return _extensionManagerStorage().extensionMetadata[functionSelector];
}
/**
* @notice Returns the extension metadata and functions for a given extension.
* @param extensionName The name of the extension to get the metadata and functions for.
* @return extension The extension metadata and functions for a given extension.
*/
function getExtension(string memory extensionName) public view virtual returns (Extension memory) {
return _getExtension(extensionName);
}
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Add a new extension to the router.
* @param _extension The extension to add.
*/
function addExtension(Extension memory _extension) public virtual onlyAuthorizedCall {
_addExtension(_extension);
}
/**
* @notice Fully replace an existing extension of the router.
* @dev The extension with name `extension.name` is the extension being replaced.
* @param _extension The extension to replace or overwrite.
*/
function replaceExtension(Extension memory _extension) public virtual onlyAuthorizedCall {
_replaceExtension(_extension);
}
/**
* @notice Remove an existing extension from the router.
* @param _extensionName The name of the extension to remove.
*/
function removeExtension(string memory _extensionName) public virtual onlyAuthorizedCall {
_removeExtension(_extensionName);
}
/**
* @notice Enables a single function in an existing extension.
* @dev Makes the given function callable on the router.
*
* @param _extensionName The name of the extension to which `extFunction` belongs.
* @param _function The function to enable.
*/
function enableFunctionInExtension(string memory _extensionName, ExtensionFunction memory _function) public virtual onlyAuthorizedCall {
_enableFunctionInExtension(_extensionName, _function);
}
/**
* @notice Disables a single function in an Extension.
*
* @param _extensionName The name of the extension to which the function of `functionSelector` belongs.
* @param _functionSelector The function to disable.
*/
function disableFunctionInExtension(string memory _extensionName, bytes4 _functionSelector) public virtual onlyAuthorizedCall {
_disableFunctionInExtension(_extensionName, _functionSelector);
}
/*///////////////////////////////////////////////////////////////
Internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Add a new extension to the router.
function _addExtension(Extension memory _extension) internal virtual {
// Check: extension namespace must not already exist.
// Check: provided extension namespace must not be empty.
// Check: provided extension implementation must be non-zero.
// Store: new extension name.
require(_canAddExtension(_extension), "ExtensionManager: cannot add extension.");
// 1. Store: metadata for extension.
_setMetadataForExtension(_extension.metadata.name, _extension.metadata);
uint256 len = _extension.functions.length;
for (uint256 i = 0; i < len; i += 1) {
// 2. Store: function for extension.
_addToFunctionMap(_extension.metadata.name, _extension.functions[i]);
// 3. Store: metadata for function.
_setMetadataForFunction(_extension.functions[i].functionSelector, _extension.metadata);
}
emit ExtensionAdded(_extension.metadata.name, _extension.metadata.implementation, _extension);
}
/// @dev Fully replace an existing extension of the router.
function _replaceExtension(Extension memory _extension) internal virtual {
// Check: extension namespace must already exist.
// Check: provided extension implementation must be non-zero.
require(_canReplaceExtension(_extension), "ExtensionManager: cannot replace extension.");
// 1. Store: metadata for extension.
_setMetadataForExtension(_extension.metadata.name, _extension.metadata);
// 2. Delete: existing extension.functions and metadata for each function.
_removeAllFunctionsFromExtension(_extension.metadata.name);
uint256 len = _extension.functions.length;
for (uint256 i = 0; i < len; i += 1) {
// 2. Store: function for extension.
_addToFunctionMap(_extension.metadata.name, _extension.functions[i]);
// 3. Store: metadata for function.
_setMetadataForFunction(_extension.functions[i].functionSelector, _extension.metadata);
}
emit ExtensionReplaced(_extension.metadata.name, _extension.metadata.implementation, _extension);
}
/// @dev Remove an existing extension from the router.
function _removeExtension(string memory _extensionName) internal virtual {
// Check: extension namespace must already exist.
// Delete: extension namespace.
require(_canRemoveExtension(_extensionName), "ExtensionManager: cannot remove extension.");
Extension memory extension = _extensionManagerStorage().extensions[_extensionName];
// 1. Delete: metadata for extension.
_deleteMetadataForExtension(_extensionName);
// 2. Delete: existing extension.functions and metadata for each function.
_removeAllFunctionsFromExtension(_extensionName);
emit ExtensionRemoved(_extensionName, extension);
}
/// @dev Makes the given function callable on the router.
function _enableFunctionInExtension(string memory _extensionName, ExtensionFunction memory _function) internal virtual {
// Check: extension namespace must already exist.
require(_canEnableFunctionInExtension(_extensionName, _function), "ExtensionManager: cannot Store: function for extension.");
// 1. Store: function for extension.
_addToFunctionMap(_extensionName, _function);
ExtensionMetadata memory metadata = _extensionManagerStorage().extensions[_extensionName].metadata;
// 2. Store: metadata for function.
_setMetadataForFunction(_function.functionSelector, metadata);
emit FunctionEnabled(_extensionName, _function.functionSelector, _function, metadata);
}
/// @dev Disables a single function in an Extension.
function _disableFunctionInExtension(string memory _extensionName, bytes4 _functionSelector) public virtual onlyAuthorizedCall {
// Check: extension namespace must already exist.
// Check: function must be mapped to provided extension.
require(_canDisableFunctionInExtension(_extensionName, _functionSelector), "ExtensionManager: cannot remove function from extension.");
ExtensionMetadata memory extMetadata = _extensionManagerStorage().extensionMetadata[_functionSelector];
// 1. Delete: function from extension.
_deleteFromFunctionMap(_extensionName, _functionSelector);
// 2. Delete: metadata for function.
_deleteMetadataForFunction(_functionSelector);
emit FunctionDisabled(_extensionName, _functionSelector, extMetadata);
}
/// @dev Returns the Extension for a given name.
function _getExtension(string memory _extensionName) internal view returns (Extension memory) {
return _extensionManagerStorage().extensions[_extensionName];
}
/// @dev Sets the ExtensionMetadata for a given extension.
function _setMetadataForExtension(string memory _extensionName, ExtensionMetadata memory _metadata) internal {
_extensionManagerStorage().extensions[_extensionName].metadata = _metadata;
}
/// @dev Deletes the ExtensionMetadata for a given extension.
function _deleteMetadataForExtension(string memory _extensionName) internal {
delete _extensionManagerStorage().extensions[_extensionName].metadata;
}
/// @dev Sets the ExtensionMetadata for a given function.
function _setMetadataForFunction(bytes4 _functionSelector, ExtensionMetadata memory _metadata) internal {
_extensionManagerStorage().extensionMetadata[_functionSelector] = _metadata;
}
/// @dev Deletes the ExtensionMetadata for a given function.
function _deleteMetadataForFunction(bytes4 _functionSelector) internal {
delete _extensionManagerStorage().extensionMetadata[_functionSelector];
}
/// @dev Adds a function to the function map of an extension.
function _addToFunctionMap(string memory _extensionName, ExtensionFunction memory _extFunction) internal virtual {
/**
* Note: `bytes4(0)` is the function selector for the `receive` function.
* So, we maintain a special fn selector-signature mismatch check for the `receive` function.
**/
bool mismatch = false;
if(_extFunction.functionSelector == bytes4(0)) {
mismatch = keccak256(abi.encode(_extFunction.functionSignature)) != keccak256(abi.encode("receive()"));
} else {
mismatch = _extFunction.functionSelector !=
bytes4(keccak256(abi.encodePacked(_extFunction.functionSignature)));
}
// Check: function selector and signature must match.
require(
!mismatch,
"ExtensionManager: fn selector and signature mismatch."
);
// Check: function must not already be mapped to an implementation.
require(
_extensionManagerStorage().extensionMetadata[_extFunction.functionSelector].implementation == address(0),
"ExtensionManager: function impl already exists."
);
// Store: name -> extension.functions map
_extensionManagerStorage().extensions[_extensionName].functions.push(_extFunction);
}
/// @dev Deletes a function from an extension's function map.
function _deleteFromFunctionMap(string memory _extensionName, bytes4 _functionSelector) internal {
ExtensionFunction[] memory extensionFunctions = _extensionManagerStorage().extensions[_extensionName].functions;
uint256 len = extensionFunctions.length;
for (uint256 i = 0; i < len; i += 1) {
if(extensionFunctions[i].functionSelector == _functionSelector) {
// Delete: particular function from name -> extension.functions map
_extensionManagerStorage().extensions[_extensionName].functions[i] = _extensionManagerStorage().extensions[_extensionName].functions[len - 1];
_extensionManagerStorage().extensions[_extensionName].functions.pop();
break;
}
}
}
/// @dev Removes all functions from an Extension.
function _removeAllFunctionsFromExtension(string memory _extensionName) internal {
ExtensionFunction[] memory functions = _extensionManagerStorage().extensions[_extensionName].functions;
// Delete: existing name -> extension.functions map
delete _extensionManagerStorage().extensions[_extensionName].functions;
for(uint256 i = 0; i < functions.length; i += 1) {
// Delete: metadata for function.
_deleteMetadataForFunction(functions[i].functionSelector);
}
}
/// @dev Returns whether a new extension can be added in the given execution context.
function _canAddExtension(Extension memory _extension) internal virtual returns (bool) {
// Check: provided extension namespace must not be empty.
require(bytes(_extension.metadata.name).length > 0, "ExtensionManager: empty name.");
// Check: extension namespace must not already exist.
// Store: new extension name.
require(_extensionManagerStorage().extensionNames.add(_extension.metadata.name), "ExtensionManager: extension already exists.");
// Check: extension implementation must be non-zero.
require(_extension.metadata.implementation != address(0), "ExtensionManager: adding extension without implementation.");
return true;
}
/// @dev Returns whether an extension can be replaced in the given execution context.
function _canReplaceExtension(Extension memory _extension) internal virtual returns (bool) {
// Check: extension namespace must already exist.
require(_extensionManagerStorage().extensionNames.contains(_extension.metadata.name), "ExtensionManager: extension does not exist.");
// Check: extension implementation must be non-zero.
require(_extension.metadata.implementation != address(0), "ExtensionManager: adding extension without implementation.");
return true;
}
/// @dev Returns whether an extension can be removed in the given execution context.
function _canRemoveExtension(string memory _extensionName) internal virtual returns (bool) {
// Check: extension namespace must already exist.
// Delete: extension namespace.
require(_extensionManagerStorage().extensionNames.remove(_extensionName), "ExtensionManager: extension does not exist.");
return true;
}
/// @dev Returns whether a function can be enabled in an extension in the given execution context.
function _canEnableFunctionInExtension(string memory _extensionName, ExtensionFunction memory) internal view virtual returns (bool) {
// Check: extension namespace must already exist.
require(_extensionManagerStorage().extensionNames.contains(_extensionName), "ExtensionManager: extension does not exist.");
return true;
}
/// @dev Returns whether a function can be disabled in an extension in the given execution context.
function _canDisableFunctionInExtension(string memory _extensionName, bytes4 _functionSelector) internal view virtual returns (bool) {
// Check: extension namespace must already exist.
require(_extensionManagerStorage().extensionNames.contains(_extensionName), "ExtensionManager: extension does not exist.");
// Check: function must be mapped to provided extension.
require(keccak256(abi.encode(_extensionManagerStorage().extensionMetadata[_functionSelector].name)) == keccak256(abi.encode(_extensionName)), "ExtensionManager: incorrect extension.");
return true;
}
/// @dev Returns the ExtensionManager storage.
function _extensionManagerStorage() internal pure returns (ExtensionManagerStorage.Data storage data) {
data = ExtensionManagerStorage.data();
}
/// @dev To override; returns whether all relevant permission and other checks are met before any upgrade.
function _isAuthorizedCallToUpgrade() internal view virtual returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./StringSet.sol";
import "../interface/IExtension.sol";
/// @title IExtensionManagerStorage
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Defined storage for managing a router's extensions.
library ExtensionManagerStorage {
/// @custom:storage-location erc7201:extension.manager.storage
bytes32 public constant EXTENSION_MANAGER_STORAGE_POSITION = keccak256(abi.encode(uint256(keccak256("extension.manager.storage")) - 1));
struct Data {
/// @dev Set of names of all extensions of the router.
StringSet.Set extensionNames;
/// @dev Mapping from extension name => `Extension` i.e. extension metadata and functions.
mapping(string => IExtension.Extension) extensions;
/// @dev Mapping from function selector => metadata of the extension the function belongs to.
mapping(bytes4 => IExtension.ExtensionMetadata) extensionMetadata;
}
/// @dev Returns access to the extension manager's storage.
function data() internal pure returns (Data storage data_) {
bytes32 position = EXTENSION_MANAGER_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.23;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
/*//////////////////////////////////////////////////////////////
SIMPLIFIED FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
uint256 internal constant MAX_UINT256 = 2**256 - 1;
uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
}
/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// Divide x * y by the denominator.
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// If x * y modulo the denominator is strictly greater than 0,
// 1 is added to round up the division of x * y by the denominator.
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
switch x
case 0 {
switch n
case 0 {
// 0 ** 0 = 1
z := scalar
}
default {
// 0 ** n = 0
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
// If n is even, store scalar in z for now.
z := scalar
}
default {
// If n is odd, store x in z for now.
z := x
}
// Shifting right by 1 is like dividing by 2.
let half := shr(1, scalar)
for {
// Shift n right by 1 before looping to halve it.
n := shr(1, n)
} n {
// Shift n right by 1 each iteration to halve it.
n := shr(1, n)
} {
// Revert immediately if x ** 2 would overflow.
// Equivalent to iszero(eq(div(xx, x), x)) here.
if shr(128, x) {
revert(0, 0)
}
// Store x squared.
let xx := mul(x, x)
// Round to the nearest number.
let xxRound := add(xx, half)
// Revert if xx + half overflowed.
if lt(xxRound, xx) {
revert(0, 0)
}
// Set x to scaled xxRound.
x := div(xxRound, scalar)
// If n is even:
if mod(n, 2) {
// Compute z * x.
let zx := mul(z, x)
// If z * x overflowed:
if iszero(eq(div(zx, x), z)) {
// Revert if x is non-zero.
if iszero(iszero(x)) {
revert(0, 0)
}
}
// Round to the nearest number.
let zxRound := add(zx, half)
// Revert if zx + half overflowed.
if lt(zxRound, zx) {
revert(0, 0)
}
// Return properly scaled zxRound.
z := div(zxRound, scalar)
}
}
}
}
}
/*//////////////////////////////////////////////////////////////
GENERAL NUMBER UTILITIES
//////////////////////////////////////////////////////////////*/
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let y := x // We start y at x, which will help us make our initial estimate.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// We check y >= 2^(k + 8) but shift right by k bits
// each branch to ensure that if x >= 256, then y >= 256.
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
// Goal was to get z*z*y within a small factor of x. More iterations could
// get y in a tighter range. Currently, we will have y in [256, 256*2^16).
// We ensured y >= 256 so that the relative difference between y and y+1 is small.
// That's not possible if x < 256 but we can just verify those cases exhaustively.
// Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
// Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
// Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
// For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
// (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
// Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
// sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
// There is no overflow risk here since y < 2^136 after the first branch above.
z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If x+1 is a perfect square, the Babylonian method cycles between
// floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
// Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
// If you don't care whether the floor or ceil square root is returned, you can remove this statement.
z := sub(z, lt(div(x, z), z))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Mod x by y. Note this will return
// 0 instead of reverting if y is zero.
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Divide x by y. Note this will return
// 0 instead of reverting if y is zero.
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Add 1 to x * y if x % y > 0. Note this will
// return 0 instead of reverting if y is zero.
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import "../IPixotchi.sol";
//import "../IRenderer.sol";
import "../IToken.sol";
/// @author thirdweb
//import { IOffers } from "../IMarketplace.sol";
/**
* @author thirdweb.com
*/
library GameStorage {
/// @custom:storage-location erc7201:offers.storage
/// @dev use chisel cli tool from foundry to evaluate this expression
/// @dev keccak256(abi.encode(uint256(keccak256("eth.pixotchi.game.storage")) - 1)) & ~bytes32(uint256(0xff))
//bytes32 constant OFFERS_STORAGE_POSITION = keccak256(abi.encode(uint256(keccak256("eth.pixotchi.game.storage")) - 1));// & ~bytes32(uint256(0xff));
//0x7b88e42357d22f249e6991bc87bae4cbb3c3a6df3597089b20afdf487007e800;
bytes32 constant GAME_STORAGE_POSITION = 0xc7fc9545a7a1c6d926eb226aca9b0331d15be911879e1d18bd76f146a8dc0000; //keccak256(abi.encode(uint256(keccak256("eth.pixotchi.game.storage")) - 1)) & ~bytes32(uint256(0xff))
struct Data {
uint256 PRECISION;// = 1 ether;
IToken token;
//uint256 _tokenIds;
uint256 _itemIds;
uint256 la;
uint256 lb;
// v staking
mapping(uint256 => uint256) ethOwed;
mapping(uint256 => uint256) plantRewardDebt;
uint256 ethAccPerShare;
uint256 totalScores;
// items/benefits for the plant, general so can be food or anything in the future.
mapping(uint256 => uint256) itemPrice;
mapping(uint256 => uint256) itemPoints;
mapping(uint256 => string) itemName;
mapping(uint256 => uint256) itemTimeExtension;
mapping(address => uint32[]) idsByOwner;
mapping(uint32 => uint32) ownerIndexById;
//mapping(address => bool) IsAuthorized;
uint256 hasTheDiamond;
//uint256 maxSupply;
bool mintIsActive;
address revShareWallet;
uint256 burnPercentage;
IRenderer renderer;
mapping(uint256 => bool) burnedPlants;
//strainCounter
uint256 strainCounter;
//mapping(uint256 => uint256) strainTotalSupply;
mapping(uint256 => uint256) mintPriceByStrain;
mapping(uint256 => uint256) strainBurned;
mapping(uint256 => uint256) strainTotalMinted;
mapping(uint256 => uint256) strainMaxSupply;
mapping(uint256 => string) strainName;
mapping(uint256 => bool) strainIsActive;
mapping(uint256 => string) strainIPFSHash;
//uint256[] strainIds;
//shop Items
uint256 shopItemCounter;
mapping(uint256 => uint256) shopItemPrice;
mapping(uint256 => uint256) shopItemTotalConsumed;
mapping(uint256 => uint256) shopItemMaxSupply;
mapping(uint256 => string) shopItemName;
mapping(uint256 => bool) shopItemIsActive;
mapping(uint256 => uint256) shopItemExpireTime;
// Plant mappings
mapping(uint256 => string) plantName;
mapping(uint256 => uint256) plantTimeUntilStarving;
mapping(uint256 => uint256) plantScore;
mapping(uint256 => uint256) plantTimeBorn;
mapping(uint256 => uint256) plantLastAttackUsed;
mapping(uint256 => uint256) plantLastAttacked;
mapping(uint256 => uint256) plantStars;
mapping(uint256 => uint256) plantStrain;
//mapping(uint256 => bool) approvedToBurn;
bool guardDisarmed;
// Shop mappings
mapping(uint256 => uint256) shop_0_Fence_EffectUntil;
mapping(uint256 => uint256) strainInitialTOD;
}
function data() internal pure returns (Data storage data_) {
bytes32 position = GAME_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
interface IERC2771Context {
function isTrustedForwarder(address forwarder) external view returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title IExtension
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Provides an `Extension` abstraction for a router's implementation contracts.
interface IExtension {
/*///////////////////////////////////////////////////////////////
Structs
//////////////////////////////////////////////////////////////*/
/**
* @notice An interface to describe an extension's metadata.
*
* @param name The unique name of the extension.
* @param metadataURI The URI where the metadata for the extension lives.
* @param implementation The implementation smart contract address of the extension.
*/
struct ExtensionMetadata {
string name;
string metadataURI;
address implementation;
}
/**
* @notice An interface to describe an extension's function.
*
* @param functionSelector The 4 byte selector of the function.
* @param functionSignature Function signature as a string. E.g. "transfer(address,address,uint256)"
*/
struct ExtensionFunction {
bytes4 functionSelector;
string functionSignature;
}
/**
* @notice An interface to describe an extension.
*
* @param metadata The extension's metadata; it's name, metadata URI and implementation contract address.
* @param functions The functions that belong to the extension.
*/
struct Extension {
ExtensionMetadata metadata;
ExtensionFunction[] functions;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IExtension.sol";
/// @title IExtensionManager
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Defined storage and API for managing a router's extensions.
interface IExtensionManager is IExtension {
/*///////////////////////////////////////////////////////////////
Events
//////////////////////////////////////////////////////////////*/
/// @dev Emitted when a extension is added.
event ExtensionAdded(string indexed name, address indexed implementation, Extension extension);
/// @dev Emitted when a extension is replaced.
event ExtensionReplaced(string indexed name, address indexed implementation, Extension extension);
/// @dev Emitted when a extension is removed.
event ExtensionRemoved(string indexed name, Extension extension);
/// @dev Emitted when a function is enabled i.e. made callable.
event FunctionEnabled(string indexed name, bytes4 indexed functionSelector, ExtensionFunction extFunction, ExtensionMetadata extMetadata);
/// @dev Emitted when a function is disabled i.e. made un-callable.
event FunctionDisabled(string indexed name, bytes4 indexed functionSelector, ExtensionMetadata extMetadata);
/*///////////////////////////////////////////////////////////////
External functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Add a new extension to the router.
* @param extension The extension to add.
*/
function addExtension(Extension memory extension) external;
/**
* @notice Fully replace an existing extension of the router.
* @dev The extension with name `extension.name` is the extension being replaced.
* @param extension The extension to replace or overwrite.
*/
function replaceExtension(Extension memory extension) external;
/**
* @notice Remove an existing extension from the router.
* @param extensionName The name of the extension to remove.
*/
function removeExtension(string memory extensionName) external;
/**
* @notice Enables a single function in an existing extension.
* @dev Makes the given function callable on the router.
*
* @param extensionName The name of the extension to which `extFunction` belongs.
* @param extFunction The function to enable.
*/
function enableFunctionInExtension(string memory extensionName, ExtensionFunction memory extFunction) external;
/**
* @notice Disables a single function in an Extension.
*
* @param extensionName The name of the extension to which the function of `functionSelector` belongs.
* @param functionSelector The function to disable.
*/
function disableFunctionInExtension(string memory extensionName, bytes4 functionSelector) external;
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IPermissions {
/**
* @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._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed 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}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed 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`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (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.
*/
function grantRole(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.
*/
function revokeRole(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`.
*/
function renounceRole(bytes32 role, address account) external;
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "./IPermissions.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IPermissionsEnumerable is IPermissions {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* [forum post](https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296)
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
interface IConfig {
}
interface IShop {
//function buyShopItem(uint256 nftId, uint256 itemId) external;
//function shopItemExists(uint256 itemId) external view returns (bool);
// function createShopItem(
// string calldata name,
// uint256 price,
// uint256 _ExpireTime
// ) external;
event ShopItemCreated(uint256 id, string name, uint256 price, uint256 ExpireTime);
//event ItemCreated(uint256 id, string name, uint256 price, uint256 points);
//event BoughtFromShop(uint256 nftId, address giver, uint256 shopItemId);
struct ShopItem {
uint256 id;
string name;
uint256 price;
uint256 ExpireTime; //for example 3days timespan.
}
struct ShopItemOwned {
uint256 id;
string name;
//uint256 price;
uint256 EffectUntil; //in the future. per owner
}
function getAllShopItem() external view returns(ShopItem[] memory);
function getPurchasedShopItems(uint256 nftId) external view returns(ShopItemOwned[] memory);
}
interface IGarden {
// Define a struct to hold plant information
struct FullItem {
uint256 id;
string name;
uint256 price;
uint256 points;
uint256 timeExtension;
}
event ItemConsumed(uint256 nftId, address giver, uint256 itemId);
event ItemCreated(uint256 id, string name, uint256 price, uint256 points);
function getAllGardenItem() external view returns(FullItem[] memory);
//function createItem(string calldata _name, uint256 _price, uint256 _points, uint256 _timeExtension) external;
//function editItem(uint256 _id, uint256 _price, uint256 _points, string calldata _name, uint256 _timeExtension) external;
}
interface INFT {
function mint(uint256 strain) external;
//function mintTo(uint256 strain, address to) external;
function burn(uint256 id) external;
event Mint(address to, uint256 strain, uint256 id);
function tokenBurnAndRedistribute(address account, uint256 amount) external;
function removeTokenIdFromOwner(uint32 tokenId, address owner) external returns (bool);
}
interface IRenderer {
function prepareTokenURI(IGame.PlantFull calldata plant, string calldata ipfsHash/*, string calldata status, uint256 level*/) external pure returns (string memory);
}
interface IGame {
function isApprovedFn(uint256 id, address wallet) external view returns (bool);
enum Status {
JOYFUL, //0
THIRSTY, //1
NEGLECTED, //2
SICK, //3
DEAD, //4,
BURNED //5
}
struct Strain {
uint256 id;
uint256 mintPrice;
uint256 totalSupply;
uint256 totalMinted;
uint256 maxSupply;
string name;
bool isActive;
uint256 getStrainTotalLeft;
uint256 strainInitialTOD;
}
struct Plant {
uint256 id;
string name;
uint256 timeUntilStarving;
uint256 score;
uint256 timePlantBorn;
uint256 lastAttackUsed;
uint256 lastAttacked;
uint256 stars;
uint256 strain;
}
struct PlantFull {
uint256 id;
string name;
uint256 timeUntilStarving;
uint256 score;
uint256 timePlantBorn;
uint256 lastAttackUsed;
uint256 lastAttacked;
uint256 stars;
uint256 strain;
Status status;
string statusStr;
uint256 level;
address owner;
uint256 rewards;
}
event Killed(
uint256 nftId,
uint256 deadId,
string loserName,
uint256 reward,
address killer,
string winnerName
);
event Attack(
uint256 attacker,
uint256 winner,
uint256 loser,
uint256 scoresWon
);
event RedeemRewards(uint256 indexed id, uint256 reward);
event Pass(uint256 from, uint256 to);
//event Mint(uint256 id);
event Played(uint256 indexed id, uint256 points, uint256 timeExtension);
event PlayedV2(uint256 indexed id, int256 points, int256 timeExtension);
// Player functions
//function mint(uint256 strain) external;
function attack(uint256 fromId, uint256 toId) external;
function kill(uint256 _deadId, uint256 _tokenId) external;
function setPlantName(uint256 _id, string calldata _name) external;
function pass(uint256 from, uint256 to) external;
function isPlantAlive(uint256 _nftId) external view returns (bool);
function pendingEth(uint256 plantId) external view returns (uint256);
function level(uint256 tokenId) external view returns (uint256);
function getStatus(uint256 plant) external view returns (IGame.Status);
function statusToString(IGame.Status status) external pure returns (string memory);
function getAllStrainInfo() external view returns(Strain[] memory);
//function createItem(string calldata _name, uint256 _price, uint256 _points, uint256 _timeExtension) external;
//function editItem(uint256 _id, uint256 _price, uint256 _points, string calldata _name, uint256 _timeExtension) external;
// Events
//event PlantCreated(uint256 indexed _plantId, address indexed _owner);
//event AttackOccurred(uint256 indexed _plantId, address indexed _attacker);
//event KillOccurred(uint256 indexed _plantId, address indexed _killer);
// event ItemCreated(uint256 indexed _itemId, string _name, uint256 _price, uint256 _points);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title ERC-7504 Dynamic Contracts: IRouter.
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Routes an incoming call to an appropriate implementation address.
/// @dev Fallback function delegateCalls `getImplementationForFunction(msg.sig)` for a given incoming call.
/// NOTE: The ERC-165 identifier for this interface is 0xce0b6013.
interface IRouter {
/**
* @notice delegateCalls the appropriate implementation address for the given incoming function call.
* @dev The implementation address to delegateCall MUST be retrieved from calling `getImplementationForFunction` with the
* incoming call's function selector.
*/
fallback() external payable;
/*///////////////////////////////////////////////////////////////
View Functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns the implementation address to delegateCall for the given function selector.
* @param _functionSelector The function selector to get the implementation address for.
* @return implementation The implementation address to delegateCall for the given function selector.
*/
function getImplementationForFunction(bytes4 _functionSelector) external view returns (address implementation);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IExtension.sol";
/// @title ERC-7504 Dynamic Contracts: IRouterState.
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Defines an API to expose a router's extensions.
interface IRouterState is IExtension {
/*///////////////////////////////////////////////////////////////
View Functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns all extensions of the Router.
* @return allExtensions An array of all extensions.
*/
function getAllExtensions() external view returns (Extension[] memory allExtensions);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IExtension.sol";
/// @title IRouterStateGetters.
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Helper view functions to inspect a router's state.
interface IRouterStateGetters is IExtension {
/*///////////////////////////////////////////////////////////////
View functions
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns the extension metadata for a given function.
* @param functionSelector The function selector to get the extension metadata for.
* @return metadata The extension metadata for a given function.
*/
function getMetadataForFunction(bytes4 functionSelector) external view returns (ExtensionMetadata memory metadata);
/**
* @notice Returns the extension metadata and functions for a given extension.
* @param extensionName The name of the extension to get the metadata and functions for.
* @return extension The extension metadata and functions for a given extension.
*/
function getExtension(string memory extensionName) external view returns (Extension memory);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
/*
.-------. .-./`) _____ __ ,-----. ,---------. _______ .---. .---..-./`)
\ _(`)_ \\ .-.')\ _\ / /.' .-, '.\ \ / __ \ | | |_ _|\ .-.')
| (_ o._)|/ `-' \.-./ ). / '/ ,-.| \ _ \`--. ,---'| ,_/ \__) | | ( ' )/ `-' \
| (_,_) / `-'`"`\ '_ .') .'; \ '_ / | : | \ ,-./ ) | '-(_{;}_)`-'`"`
| '-.-' .---.(_ (_) _) ' | _`,/ \ _/ | :_ _: \ '_ '`) | (_,_) .---.
| | | | / \ \: ( '\_/ \ ; (_I_) > (_) ) __ | _ _--. | | |
| | | | `-'`-' \\ `"/ \ ) / (_(=)_)( . .-'_/ )|( ' ) | | | |
/ ) | | / / \ \'. \_/``".' (_I_) `-'`-' / (_{;}_)| | | |
`---' '---''--' '----' '-----' '---' `._____.' '(_,_) '---' '---'
https://t.me/Pixotchi
https://twitter.com/pixotchi
https://pixotchi.tech/
*/
interface IToken {
function balanceOf(
address tokenOwner
) external view returns (uint256 balance);
function totalSupply() external view returns (uint256 supply);
function transfer(
address to,
uint256 tokens
) external returns (bool success);
function transferFrom(
address from,
address to,
uint256 tokens
) external returns (bool success);
}
// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;
import "../../lib/Address.sol";
library InitStorage {
/// @custom:storage-location erc7201:init.storage
/// @dev keccak256(abi.encode(uint256(keccak256("init.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 constant INIT_STORAGE_POSITION = 0x322cf19c484104d3b1a9c2982ebae869ede3fa5f6c4703ca41b9a48c76ee0300;
/// @dev Layout of the entrypoint contract's storage.
struct Data {
uint8 initialized;
bool initializing;
}
/// @dev Returns the entrypoint contract's data at the relevant storage location.
function data() internal pure returns (Data storage data_) {
bytes32 position = INIT_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
abstract contract Initializable {
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
uint8 _initialized = _initStorage().initialized;
bool _initializing = _initStorage().initializing;
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initStorage().initialized = 1;
if (isTopLevelCall) {
_initStorage().initializing = true;
}
_;
if (isTopLevelCall) {
_initStorage().initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
* initialization step. This is essential to configure modules that are added through upgrades and that require
* initialization.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*/
modifier reinitializer(uint8 version) {
uint8 _initialized = _initStorage().initialized;
bool _initializing = _initStorage().initializing;
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initStorage().initialized = version;
_initStorage().initializing = true;
_;
_initStorage().initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initStorage().initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
uint8 _initialized = _initStorage().initialized;
bool _initializing = _initStorage().initializing;
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initStorage().initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/// @dev Returns the InitStorage storage.
function _initStorage() internal pure returns (InitStorage.Data storage data) {
data = InitStorage.data();
}
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../interface/IPermissions.sol";
import "../../lib/Strings.sol";
/**
* @title Permissions
* @dev This contracts provides extending-contracts with role-based access control mechanisms
*/
library PermissionsStorage {
/// @custom:storage-location erc7201:permissions.storage
/// @dev keccak256(abi.encode(uint256(keccak256("permissions.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 public constant PERMISSIONS_STORAGE_POSITION =
0x0a7b0f5c59907924802379ebe98cdc23e2ee7820f63d30126e10b3752010e500;
struct Data {
/// @dev Map from keccak256 hash of a role => a map from address => whether address has role.
mapping(bytes32 => mapping(address => bool)) _hasRole;
/// @dev Map from keccak256 hash of a role to role admin. See {getRoleAdmin}.
mapping(bytes32 => bytes32) _getRoleAdmin;
}
function data() internal pure returns (Data storage data_) {
bytes32 position = PERMISSIONS_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
contract Permissions is IPermissions {
/// @dev Default admin role for all roles. Only accounts with this role can grant/revoke other roles.
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @dev Modifier that checks if an account has the specified role; reverts otherwise.
modifier onlyRole(bytes32 role) {
_checkRole(role, _msgSender());
_;
}
/**
* @notice Checks whether an account has a particular role.
* @dev Returns `true` if `account` has been granted `role`.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account for which the role is being checked.
*/
function hasRole(bytes32 role, address account) public view override returns (bool) {
return _permissionsStorage()._hasRole[role][account];
}
/**
* @notice Checks whether an account has a particular role;
* role restrictions can be swtiched on and off.
*
* @dev Returns `true` if `account` has been granted `role`.
* Role restrictions can be swtiched on and off:
* - If address(0) has ROLE, then the ROLE restrictions
* don't apply.
* - If address(0) does not have ROLE, then the ROLE
* restrictions will apply.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account for which the role is being checked.
*/
function hasRoleWithSwitch(bytes32 role, address account) public view returns (bool) {
if (!_permissionsStorage()._hasRole[role][address(0)]) {
return _permissionsStorage()._hasRole[role][account];
}
return true;
}
/**
* @notice Returns the admin role that controls the specified role.
* @dev See {grantRole} and {revokeRole}.
* To change a role's admin, use {_setRoleAdmin}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*/
function getRoleAdmin(bytes32 role) external view override returns (bytes32) {
return _permissionsStorage()._getRoleAdmin[role];
}
/**
* @notice Grants a role to an account, if not previously granted.
* @dev Caller must have admin role for the `role`.
* Emits {RoleGranted Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account to which the role is being granted.
*/
function grantRole(bytes32 role, address account) public virtual override {
_checkRole(_permissionsStorage()._getRoleAdmin[role], _msgSender());
if (_permissionsStorage()._hasRole[role][account]) {
revert("Can only grant to non holders");
}
_setupRole(role, account);
}
/**
* @notice Revokes role from an account.
* @dev Caller must have admin role for the `role`.
* Emits {RoleRevoked Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account from which the role is being revoked.
*/
function revokeRole(bytes32 role, address account) public virtual override {
_checkRole(_permissionsStorage()._getRoleAdmin[role], _msgSender());
_revokeRole(role, account);
}
/**
* @notice Revokes role from the account.
* @dev Caller must have the `role`, with caller being the same as `account`.
* Emits {RoleRevoked Event}.
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param account Address of the account from which the role is being revoked.
*/
function renounceRole(bytes32 role, address account) public virtual override {
if (_msgSender() != account) {
revert("Can only renounce for self");
}
_revokeRole(role, account);
}
/// @dev Sets `adminRole` as `role`'s admin role.
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = _permissionsStorage()._getRoleAdmin[role];
_permissionsStorage()._getRoleAdmin[role] = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/// @dev Sets up `role` for `account`
function _setupRole(bytes32 role, address account) internal virtual {
_permissionsStorage()._hasRole[role][account] = true;
emit RoleGranted(role, account, _msgSender());
}
/// @dev Revokes `role` from `account`
function _revokeRole(bytes32 role, address account) internal virtual {
_checkRole(role, account);
delete _permissionsStorage()._hasRole[role][account];
emit RoleRevoked(role, account, _msgSender());
}
/// @dev Checks `role` for `account`. Reverts with a message including the required role.
function _checkRole(bytes32 role, address account) internal view virtual {
if (!_permissionsStorage()._hasRole[role][account]) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/// @dev Checks `role` for `account`. Reverts with a message including the required role.
function _checkRoleWithSwitch(bytes32 role, address account) internal view virtual {
if (!hasRoleWithSwitch(role, account)) {
revert(
string(
abi.encodePacked(
"Permissions: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
function _msgSender() internal view virtual returns (address sender) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/// @dev Returns the Permissions storage.
function _permissionsStorage() internal pure returns (PermissionsStorage.Data storage data) {
data = PermissionsStorage.data();
}
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
import "../interface/IPermissionsEnumerable.sol";
import "./Permissions.sol";
/**
* @title PermissionsEnumerable
* @dev This contracts provides extending-contracts with role-based access control mechanisms.
* Also provides interfaces to view all members with a given role, and total count of members.
*/
library PermissionsEnumerableStorage {
/// @custom:storage-location erc7201:extension.manager.storage
bytes32 public constant PERMISSIONS_ENUMERABLE_STORAGE_POSITION =
keccak256(abi.encode(uint256(keccak256("permissions.enumerable.storage")) - 1)) & ~bytes32(uint256(0xff));
/**
* @notice A data structure to store data of members for a given role.
*
* @param index Current index in the list of accounts that have a role.
* @param members map from index => address of account that has a role
* @param indexOf map from address => index which the account has.
*/
struct RoleMembers {
uint256 index;
mapping(uint256 => address) members;
mapping(address => uint256) indexOf;
}
struct Data {
/// @dev map from keccak256 hash of a role to its members' data. See {RoleMembers}.
mapping(bytes32 => RoleMembers) roleMembers;
}
function data() internal pure returns (Data storage data_) {
bytes32 position = PERMISSIONS_ENUMERABLE_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
contract PermissionsEnumerable is IPermissionsEnumerable, Permissions {
/**
* @notice Returns the role-member from a list of members for a role,
* at a given index.
* @dev Returns `member` who has `role`, at `index` of role-members list.
* See struct {RoleMembers}, and mapping {roleMembers}
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
* @param index Index in list of current members for the role.
*
* @return member Address of account that has `role`
*/
function getRoleMember(bytes32 role, uint256 index) external view override returns (address member) {
uint256 currentIndex = _permissionsEnumerableStorage().roleMembers[role].index;
uint256 check;
for (uint256 i = 0; i < currentIndex; i += 1) {
if (_permissionsEnumerableStorage().roleMembers[role].members[i] != address(0)) {
if (check == index) {
member = _permissionsEnumerableStorage().roleMembers[role].members[i];
return member;
}
check += 1;
} else if (
hasRole(role, address(0)) && i == _permissionsEnumerableStorage().roleMembers[role].indexOf[address(0)]
) {
check += 1;
}
}
}
/**
* @notice Returns total number of accounts that have a role.
* @dev Returns `count` of accounts that have `role`.
* See struct {RoleMembers}, and mapping {roleMembers}
*
* @param role keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
*
* @return count Total number of accounts that have `role`
*/
function getRoleMemberCount(bytes32 role) external view override returns (uint256 count) {
uint256 currentIndex = _permissionsEnumerableStorage().roleMembers[role].index;
for (uint256 i = 0; i < currentIndex; i += 1) {
if (_permissionsEnumerableStorage().roleMembers[role].members[i] != address(0)) {
count += 1;
}
}
if (hasRole(role, address(0))) {
count += 1;
}
}
/// @dev Revokes `role` from `account`, and removes `account` from {roleMembers}
/// See {_removeMember}
function _revokeRole(bytes32 role, address account) internal virtual override {
super._revokeRole(role, account);
_removeMember(role, account);
}
/// @dev Grants `role` to `account`, and adds `account` to {roleMembers}
/// See {_addMember}
function _setupRole(bytes32 role, address account) internal virtual override {
super._setupRole(role, account);
_addMember(role, account);
}
/// @dev adds `account` to {roleMembers}, for `role`
function _addMember(bytes32 role, address account) internal {
uint256 idx = _permissionsEnumerableStorage().roleMembers[role].index;
_permissionsEnumerableStorage().roleMembers[role].index += 1;
_permissionsEnumerableStorage().roleMembers[role].members[idx] = account;
_permissionsEnumerableStorage().roleMembers[role].indexOf[account] = idx;
}
/// @dev removes `account` from {roleMembers}, for `role`
function _removeMember(bytes32 role, address account) internal {
uint256 idx = _permissionsEnumerableStorage().roleMembers[role].indexOf[account];
delete _permissionsEnumerableStorage().roleMembers[role].members[idx];
delete _permissionsEnumerableStorage().roleMembers[role].indexOf[account];
}
/// @dev Returns the PermissionsEnumerable storage.
function _permissionsEnumerableStorage() internal pure returns (PermissionsEnumerableStorage.Data storage data) {
data = PermissionsEnumerableStorage.data();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
/// @author pixotchi
// $$\ $$\ $$\ $$\
// \__| $$ | $$ | \__|
// $$$$$$\ $$\ $$\ $$\ $$$$$$\ $$$$$$\ $$$$$$$\ $$$$$$$\ $$\
// $$ __$$\ $$ |\$$\ $$ |$$ __$$\ \_$$ _| $$ _____|$$ __$$\ $$ |
// $$ / $$ |$$ | \$$$$ / $$ / $$ | $$ | $$ / $$ | $$ |$$ |
// $$ | $$ |$$ | $$ $$< $$ | $$ | $$ |$$\ $$ | $$ | $$ |$$ |
// $$$$$$$ |$$ |$$ /\$$\ \$$$$$$ | \$$$$ |\$$$$$$$\ $$ | $$ |$$ |
// $$ ____/ \__|\__/ \__| \______/ \____/ \_______|\__| \__|\__|
// $$ |
// $$ |
// \__|
// ====== Special thanks to ======
// $$\ $$\ $$\ $$\ $$\
// $$ | $$ | \__| $$ | $$ |
// $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
// \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
// $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
// $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
// \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
// \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/
// ====== and to ======
// |"| |"| # # # ___ _ _ _ _ | ___
// vvv _|_|_ ` _ , ' ` _ , ' _|_|_ #=ooO=========Ooo=# # <_*_> o' \,=./ `o o' \,=./ `o |.===. /\#/\
// (0~0) (o o) - (o)o) - - (o)o) - (o o) # \\ (o o) // # # (o o) (o o) (o o) {}o o{} /(o o)\
// ooO--(_)--Ooo-ooO--(_)--Ooo--ooO'(_)--Ooo--ooO'(_)--Ooo-ooO--(_)--Ooo---------(_)---------8---(_)--Ooo-ooO--(_)--Ooo-ooO--(_)--Ooo-ooO--(_)--Ooo-ooO--(_)--Ooo-
// ▄▄▄▄▄▄▄▄▄▄▄ ▄▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄ ▄
// ▐░░░░░░░░░░░▌▐░░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░▌ ▐░▌
// ▐░█▀▀▀▀▀▀▀█░▌▐░▌░▌ ▐░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀█░▌ ▀▀▀▀█░█▀▀▀▀ ▐░▌░▌ ▐░▌
// ▐░▌ ▐░▌▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌
// ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌
// ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌
// ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌
// ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌
// ▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌ ▐░▌ ▄▄▄▄█░█▄▄▄▄ ▐░▌ ▐░▐░▌
// ▐░░░░░░░░░░░▌▐░▌ ▐░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░░▌
// ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀
//
// ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄ ▄▄ ▄▄ ▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄
// ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░▌ ▐░░▌▐░░▌ ▐░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌
// ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░▌░▌ ▐░▐░▌▐░▌░▌ ▐░▐░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌
// ▐░▌ ▐░▌ ▐░▌▐░▌▐░▌ ▐░▌▐░▌▐░▌▐░▌ ▐░▌▐░▌▐░▌ ▐░▌ ▐░▌
// ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌ ▐░▐░▌ ▐░▌▐░▌ ▐░▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌
// ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌
// ▀▀▀▀▀▀▀▀▀█░▌▐░▌ ▐░▌▐░▌ ▀ ▐░▌▐░▌ ▀ ▐░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀█░█▀▀
// ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌
// ▄▄▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌
// ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌
// ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀
//
import {BaseRouter, IRouter, IRouterState} from "../../lib/dynamic-contracts/src/presets/BaseRouter.sol";
import "../../lib/contracts/contracts/extension/upgradeable/PermissionsEnumerable.sol";
import "../../lib/contracts/contracts/extension/upgradeable/Initializable.sol";
import "../../lib/contracts/contracts/extension/upgradeable/init/ReentrancyGuardInit.sol";
import "../../lib/contracts/contracts/extension/upgradeable/ReentrancyGuard.sol";
import "../../lib/contracts/contracts/extension/upgradeable/ERC2771ContextUpgradeable.sol";
import "../utils/FixedPointMathLib.sol";
import "../game/GameStorage.sol";
contract PixotchiRouter is
Initializable,
BaseRouter,
PermissionsEnumerable,
ReentrancyGuardInit,
ReentrancyGuard,
ERC2771ContextUpgradeable
{
/// @dev Only EXTENSION_ROLE holders can perform upgrades.
bytes32 private constant EXTENSION_ROLE = keccak256("EXTENSION_ROLE");
bytes32 private constant MODULE_TYPE = bytes32("PixotchiRouter");
uint256 private constant VERSION = 1;
/// @dev We accept constructor params as a struct to avoid `Stack too deep` errors.
struct SimpleRouterConstructorParams {
Extension[] extensions;
}
constructor(
SimpleRouterConstructorParams memory _simpleRouterV3Params
) BaseRouter(_simpleRouterV3Params.extensions) {
__BaseRouter_init();
}
receive() external payable {
GameStorage.Data storage _s = GameStorage.data();
_s.ethAccPerShare += FixedPointMathLib.mulDivDown(msg.value, _s.PRECISION, _s.totalScores);
}
/// @dev Initializes the contract, like a constructor.
function initializeRouter(
) external initializer {
__ReentrancyGuard_init();
address _defaultAdmin = 0x44e156CBb4506cee55A96b45D10A77806E012469;
_setupRole(DEFAULT_ADMIN_ROLE, _defaultAdmin);
_setupRole(EXTENSION_ROLE, _defaultAdmin);
_setRoleAdmin(EXTENSION_ROLE, EXTENSION_ROLE);
}
/*///////////////////////////////////////////////////////////////
Generic contract logic
//////////////////////////////////////////////////////////////*/
/// @dev Returns the type of the contract.
function contractType() external pure returns (bytes32) {
return MODULE_TYPE;
}
/// @dev Returns the version of the contract.
function contractVersion() external pure returns (uint8) {
return uint8(VERSION);
}
/*///////////////////////////////////////////////////////////////
Overridable Permissions
//////////////////////////////////////////////////////////////*/
/// @dev Checks whether an account has a particular role.
function _hasRole(bytes32 _role, address _account) internal view returns (bool) {
PermissionsStorage.Data storage data = PermissionsStorage.data();
return data._hasRole[_role][_account];
}
/// @dev Returns whether all relevant permission and other checks are met before any upgrade.
function _isAuthorizedCallToUpgrade() internal view virtual override returns (bool) {
return _hasRole(EXTENSION_ROLE, msg.sender);
}
function _msgSender()
internal
view
override(ERC2771ContextUpgradeable, Permissions)
returns (address sender)
{
return ERC2771ContextUpgradeable._msgSender();
}
function _msgData() internal view override(ERC2771ContextUpgradeable, Permissions)
returns (bytes calldata) {
return ERC2771ContextUpgradeable._msgData();
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
library ReentrancyGuardStorage {
/// @custom:storage-location erc7201:reentrancy.guard.storage
/// @dev keccak256(abi.encode(uint256(keccak256("reentrancy.guard.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 public constant REENTRANCY_GUARD_STORAGE_POSITION =
0x1d281c488dae143b6ea4122e80c65059929950b9c32f17fc57be22089d9c3b00;
struct Data {
uint256 _status;
}
function data() internal pure returns (Data storage data_) {
bytes32 position = REENTRANCY_GUARD_STORAGE_POSITION;
assembly {
data_.slot := position
}
}
}
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
constructor() {
_reentrancyGuardStorage()._status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_reentrancyGuardStorage()._status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_reentrancyGuardStorage()._status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_reentrancyGuardStorage()._status = _NOT_ENTERED;
}
/// @dev Returns the ReentrancyGuard storage.
function _reentrancyGuardStorage() internal pure returns (ReentrancyGuardStorage.Data storage data) {
data = ReentrancyGuardStorage.data();
}
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import { ReentrancyGuardStorage } from "../ReentrancyGuard.sol";
import "../Initializable.sol";
contract ReentrancyGuardInit is Initializable {
uint256 private constant _NOT_ENTERED = 1;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage.Data storage data = ReentrancyGuardStorage.data();
data._status = _NOT_ENTERED;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../interface/IRouter.sol";
/// @title ERC-7504 Dynamic Contracts: Router.
/// @author thirdweb (https://github.com/thirdweb-dev/dynamic-contracts)
/// @notice Routes an incoming call to an appropriate implementation address.
abstract contract Router is IRouter {
/**
* @notice delegateCalls the appropriate implementation address for the given incoming function call.
* @dev The implementation address to delegateCall MUST be retrieved from calling `getImplementationForFunction` with the
* incoming call's function selector.
*/
fallback() external payable virtual {
if(msg.data.length == 0) return;
address implementation = getImplementationForFunction(msg.sig);
require(implementation != address(0), "Router: function does not exist.");
_delegate(implementation);
}
/// @dev delegateCalls an `implementation` smart contract.
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @notice Returns the implementation address to delegateCall for the given function selector.
* @param _functionSelector The function selector to get the implementation address for.
* @return implementation The implementation address to delegateCall for the given function selector.
*/
function getImplementationForFunction(bytes4 _functionSelector) public view virtual returns (address implementation);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./utils/Bytecode.sol";
/**
@title A key-value storage with auto-generated keys for storing chunks of data with a lower write & read cost.
@author Agustin Aguilar <aa@horizon.io>
Readme: https://github.com/0xsequence/sstore2#readme
*/
library SSTORE2 {
error WriteError();
/**
@notice Stores `_data` and returns `pointer` as key for later retrieval
@dev The pointer is a contract address with `_data` as code
@param _data to be written
@return pointer Pointer to the written `_data`
*/
function write(bytes memory _data) internal returns (address pointer) {
// Append 00 to _data so contract can't be called
// Build init code
bytes memory code = Bytecode.creationCodeFor(
abi.encodePacked(
hex'00',
_data
)
);
// Deploy contract using create
assembly { pointer := create(0, add(code, 32), mload(code)) }
// Address MUST be non-zero
if (pointer == address(0)) revert WriteError();
}
/**
@notice Reads the contents of the `_pointer` code as data, skips the first byte
@dev The function is intended for reading pointers generated by `write`
@param _pointer to be read
@return data read from `_pointer` contract
*/
function read(address _pointer) internal view returns (bytes memory) {
return Bytecode.codeAt(_pointer, 1, type(uint256).max);
}
/**
@notice Reads the contents of the `_pointer` code as data, skips the first byte
@dev The function is intended for reading pointers generated by `write`
@param _pointer to be read
@param _start number of bytes to skip
@return data read from `_pointer` contract
*/
function read(address _pointer, uint256 _start) internal view returns (bytes memory) {
return Bytecode.codeAt(_pointer, _start + 1, type(uint256).max);
}
/**
@notice Reads the contents of the `_pointer` code as data, skips the first byte
@dev The function is intended for reading pointers generated by `write`
@param _pointer to be read
@param _start number of bytes to skip
@param _end index before which to end extraction
@return data read from `_pointer` contract
*/
function read(address _pointer, uint256 _start, uint256 _end) internal view returns (bytes memory) {
return Bytecode.codeAt(_pointer, _start + 1, _end + 1);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library StringSet {
struct Set {
// Storage of set values
string[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(string => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, string memory value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, string memory value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
string memory lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, string memory value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (string memory) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (string[] memory) {
return set._values;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Set storage set, string memory value) internal returns (bool) {
return _add(set, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Set storage set, string memory value) internal returns (bool) {
return _remove(set, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Set storage set, string memory value) internal view returns (bool) {
return _contains(set, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Set storage set) internal view returns (uint256) {
return _length(set);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Set storage set, uint256 index) internal view returns (string memory) {
return _at(set, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Set storage set) internal view returns (string[] memory) {
return _values(set);
}
}
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @author thirdweb
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
/// and the alphabets are capitalized conditionally according to
/// https://eips.ethereum.org/EIPS/eip-55
function toHexStringChecksummed(address value) internal pure returns (string memory str) {
str = toHexString(value);
/// @solidity memory-safe-assembly
assembly {
let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
let o := add(str, 0x22)
let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
let t := shl(240, 136) // `0b10001000 << 240`
for {
let i := 0
} 1 {
} {
mstore(add(i, i), mul(t, byte(i, hashed)))
i := add(i, 1)
if eq(i, 20) {
break
}
}
mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
o := add(o, 0x20)
mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
function toHexString(address value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(address value) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
str := mload(0x40)
// Allocate the memory.
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x28 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
mstore(0x40, add(str, 0x80))
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
str := add(str, 2)
mstore(str, 40)
let o := add(str, 0x20)
mstore(add(o, 40), 0)
value := shl(96, value)
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for {
let i := 0
} 1 {
} {
let p := add(o, add(i, i))
let temp := byte(i, value)
mstore8(add(p, 1), mload(and(temp, 15)))
mstore8(p, mload(shr(4, temp)))
i := add(i, 1)
if eq(i, 20) {
break
}
}
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexString(bytes memory raw) internal pure returns (string memory str) {
str = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
let length := mload(raw)
str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
mstore(str, add(length, length)) // Store the length of the output.
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let o := add(str, 0x20)
let end := add(raw, length)
for {
} iszero(eq(raw, end)) {
} {
raw := add(raw, 1)
mstore8(add(o, 1), mload(and(mload(raw), 15)))
mstore8(o, mload(and(shr(4, mload(raw)), 15)))
o := add(o, 2)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate the memory.
}
}
}
{
"compilationTarget": {
"src/entrypoint/PixotchiRouter.sol": "PixotchiRouter"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@chainlink/=lib/contracts/lib/chainlink/",
":@ds-test/=lib/contracts/lib/ds-test/src/",
":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
":@rari-capital/solmate/=lib/contracts/lib/seaport/lib/solmate/",
":@seaport/=lib/contracts/lib/seaport/contracts/",
":@solady/=lib/contracts/lib/solady/",
":@std/=lib/contracts/lib/forge-std/src/",
":@thirdweb-dev/=node_modules/@thirdweb-dev/",
":@thirdweb-dev/dynamic-contracts/=lib/contracts/lib/dynamic-contracts/",
":ERC721A-Upgradeable/=lib/contracts/lib/ERC721A-Upgradeable/contracts/",
":ERC721A/=lib/contracts/lib/ERC721A/contracts/",
":chainlink/=lib/contracts/lib/chainlink/contracts/",
":contracts/=lib/contracts/contracts/",
":ds-test/=lib/contracts/lib/ds-test/src/",
":dynamic-contracts/=lib/dynamic-contracts/src/",
":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
":erc721a-upgradeable/=lib/contracts/lib/ERC721A-Upgradeable/",
":erc721a/=lib/contracts/lib/ERC721A/",
":forge-std/=lib/forge-std/src/",
":lib/sstore2/=lib/contracts/lib/dynamic-contracts/lib/sstore2/",
":murky/=lib/contracts/lib/murky/",
":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":openzeppelin/=lib/contracts/lib/openzeppelin-contracts-upgradeable/contracts/",
":seaport-core/=lib/contracts/lib/seaport-core/src/",
":seaport-sol/=lib/contracts/lib/seaport-sol/src/",
":seaport-types/=lib/contracts/lib/seaport-types/src/",
":seaport/=lib/contracts/lib/seaport/",
":solady/=lib/contracts/lib/solady/src/",
":solarray/=lib/contracts/lib/seaport/lib/solarray/src/",
":solmate/=lib/contracts/lib/seaport/lib/solmate/src/",
":sstore2/=lib/dynamic-contracts/lib/sstore2/contracts/",
":thirdweb-contracts/=lib/thirdweb-contracts/contracts/"
]
}
[{"inputs":[{"components":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension[]","name":"extensions","type":"tuple[]"}],"internalType":"struct PixotchiRouter.SimpleRouterConstructorParams","name":"_simpleRouterV3Params","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"_size","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"InvalidCodeAtRange","type":"error"},{"inputs":[],"name":"WriteError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"address","name":"implementation","type":"address"},{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"indexed":false,"internalType":"struct IExtension.Extension","name":"extension","type":"tuple"}],"name":"ExtensionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"name","type":"string"},{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"indexed":false,"internalType":"struct IExtension.Extension","name":"extension","type":"tuple"}],"name":"ExtensionRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"address","name":"implementation","type":"address"},{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"indexed":false,"internalType":"struct IExtension.Extension","name":"extension","type":"tuple"}],"name":"ExtensionReplaced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"indexed":false,"internalType":"struct IExtension.ExtensionMetadata","name":"extMetadata","type":"tuple"}],"name":"FunctionDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"indexed":false,"internalType":"struct IExtension.ExtensionFunction","name":"extFunction","type":"tuple"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"indexed":false,"internalType":"struct IExtension.ExtensionMetadata","name":"extMetadata","type":"tuple"}],"name":"FunctionEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_extensionName","type":"string"},{"internalType":"bytes4","name":"_functionSelector","type":"bytes4"}],"name":"_disableFunctionInExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension","name":"_extension","type":"tuple"}],"name":"addExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractType","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"contractVersion","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"defaultExtensions","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_extensionName","type":"string"},{"internalType":"bytes4","name":"_functionSelector","type":"bytes4"}],"name":"disableFunctionInExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_extensionName","type":"string"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction","name":"_function","type":"tuple"}],"name":"enableFunctionInExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllExtensions","outputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension[]","name":"allExtensions","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"extensionName","type":"string"}],"name":"getExtension","outputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_functionSelector","type":"bytes4"}],"name":"getImplementationForFunction","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"}],"name":"getMetadataForFunction","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"member","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRoleWithSwitch","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initializeRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_extensionName","type":"string"}],"name":"removeExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"metadataURI","type":"string"},{"internalType":"address","name":"implementation","type":"address"}],"internalType":"struct IExtension.ExtensionMetadata","name":"metadata","type":"tuple"},{"components":[{"internalType":"bytes4","name":"functionSelector","type":"bytes4"},{"internalType":"string","name":"functionSignature","type":"string"}],"internalType":"struct IExtension.ExtensionFunction[]","name":"functions","type":"tuple[]"}],"internalType":"struct IExtension.Extension","name":"_extension","type":"tuple"}],"name":"replaceExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]