From 10f36356ab3970bccc2ee6b1196383d3dd4d9484 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Tue, 17 Jan 2023 11:09:01 -0300 Subject: [PATCH 01/14] wip(structure): changing the structure to modular libs --- .env.example | 2 + .gitignore | 1 + README.md | 37 +++--- brownie-config.yaml | 4 +- contracts/diamond/Diamond.sol | 7 +- .../{diamond => }/facets/DiamondCutFacet.sol | 0 .../facets/DiamondLoupeFacet.sol | 0 .../InventoryFacet.sol} | 109 ++---------------- .../{diamond => }/facets/OwnershipFacet.sol | 0 contracts/interfaces/IDiamond.sol | 8 ++ .../{diamond => }/interfaces/IDiamondCut.sol | 0 .../interfaces/IDiamondLoupe.sol | 0 .../{diamond => }/interfaces/IERC165.sol | 0 .../{diamond => }/interfaces/IERC173.sol | 2 - contracts/interfaces/IInventory.sol | 98 ++++++++++++++++ .../{diamond => }/libraries/LibDiamond.sol | 0 contracts/libraries/LibInventory.sol | 67 +++++++++++ contracts/mock/ShibaERC721.sol | 34 ++++++ scripts/deploy_shiba_erc721.py | 10 ++ scripts/mint_shiba_nft.py | 13 +++ 20 files changed, 271 insertions(+), 121 deletions(-) create mode 100644 .env.example rename contracts/{diamond => }/facets/DiamondCutFacet.sol (100%) rename contracts/{diamond => }/facets/DiamondLoupeFacet.sol (100%) rename contracts/{inventory/Inventory.sol => facets/InventoryFacet.sol} (77%) rename contracts/{diamond => }/facets/OwnershipFacet.sol (100%) create mode 100644 contracts/interfaces/IDiamond.sol rename contracts/{diamond => }/interfaces/IDiamondCut.sol (100%) rename contracts/{diamond => }/interfaces/IDiamondLoupe.sol (100%) rename contracts/{diamond => }/interfaces/IERC165.sol (100%) rename contracts/{diamond => }/interfaces/IERC173.sol (89%) create mode 100644 contracts/interfaces/IInventory.sol rename contracts/{diamond => }/libraries/LibDiamond.sol (100%) create mode 100644 contracts/libraries/LibInventory.sol create mode 100644 contracts/mock/ShibaERC721.sol create mode 100644 scripts/deploy_shiba_erc721.py create mode 100644 scripts/mint_shiba_nft.py diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..37f8520 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +WEB3_INFURA_PROJECT_ID=YOUR_PROJECT_ID_HERE +POLYGONSCAN_TOKEN= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5b888a3..fc2fed0 100644 --- a/.gitignore +++ b/.gitignore @@ -149,3 +149,4 @@ prod.test.env dev.test.env scratch/ +.idea diff --git a/README.md b/README.md index 7562bb6..2d5ab66 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ Main repo for Game7 contracts First, set up a Python3 environment: -- Check if you have Python3 installed on your system: `python3 --version`. -- If the above command errors out, you need to install Python3. You can find instructions for how to -do this at https://python.org. -- Create a Python virtual environment in the root of this directory: `python3 -m venv .game7` -- Activate the virtual environment: `source .game7/bin/activate` (when you are finished working in this -code base, you can deactivate the virtual environment using the `deactivate` command). -- Install the `game7ctl` package: `pip install -e game7ctl/` +- Check if you have Python3 installed on your system: `python3 --version`. +- If the above command errors out, you need to install Python3. You can find instructions for how to + do this at https://python.org. +- Create a Python virtual environment in the root of this directory: `python3 -m venv .game7` +- Activate the virtual environment: `source .game7/bin/activate` (when you are finished working in this + code base, you can deactivate the virtual environment using the `deactivate` command). +- Install the `game7ctl` package: `pip install -e game7ctl/` Following these steps will make the `game7ctl` command available in your shell. You can use this command-line tool to deploy and interact with the smart contracts in this repository. For more details: @@ -31,7 +31,7 @@ To compile the smart contracts using `brownie`, run the following command from t brownie compile ``` -To set up a *development* environment, you have to also install the developer dependencies using: +To set up a _development_ environment, you have to also install the developer dependencies using: ``` pip install -e "game7ctl/[dev]" @@ -56,20 +56,20 @@ For example, after modifying `InventoryFacet`, you would run: moonworm generate-brownie -p . -o game7ctl/game7ctl -n InventoryFacet ``` -- - - +--- ## Deploying contracts ### `game7ctl` Once you have set up `game7ctl`, you can use it to deploy the contracts in this repository. For example, -to deploy the Inventory contract as a Diamond proxy, you would use the `game7ctl core inventory-gogogo` command. +to deploy the Inventory contract as a Diamond proxy, you would use the `game7ctl core inventory-facet-deploy` command. To see all the parameters you can pass in the deployment, run: ``` -$ game7ctl core inventory-gogogo --help -usage: game7ctl inventory-gogogo [-h] --network NETWORK [--address ADDRESS] --sender SENDER [--password PASSWORD] [--gas-price GAS_PRICE] [--max-fee-per-gas MAX_FEE_PER_GAS] +$ game7ctl core inventory-facet-deploy --help +usage: game7ctl inventory-facet-deploy [-h] --network NETWORK [--address ADDRESS] --sender SENDER [--password PASSWORD] [--gas-price GAS_PRICE] [--max-fee-per-gas MAX_FEE_PER_GAS] [--max-priority-fee-per-gas MAX_PRIORITY_FEE_PER_GAS] [--confirmations CONFIRMATIONS] [--nonce NONCE] [--value VALUE] [--verbose] --admin-terminus-address ADMIN_TERMINUS_ADDRESS --admin-terminus-pool-id ADMIN_TERMINUS_POOL_ID --subject-erc721-address SUBJECT_ERC721_ADDRESS [--diamond-cut-address DIAMOND_CUT_ADDRESS] [--diamond-address DIAMOND_ADDRESS] [--diamond-loupe-address DIAMOND_LOUPE_ADDRESS] @@ -129,7 +129,7 @@ brownie networks add Polygon $NETWORK_NAME host=$JSONRPC_URL chainid=137 explore The only keys which are not optional are `chainid` and `host`. -Then, you could pass `--network $NETWORK_NAME` as an argument to `game7ctl core inventory-gogogo`. +Then, you could pass `--network $NETWORK_NAME` as an argument to `game7ctl core inventory-facet-deploy`. ##### `--sender` @@ -147,3 +147,14 @@ Then you can pass `--sender $ACCOUNT_NAME` to `game7ctl`. The preferred way of using `--sender` is still by passing a keystore file. `brownie` will always prompt you to unlock the account with a password. + +##### Deployment Example: + +If you follow all the explanations above, you should be able to deploy the Inventory contract as a Diamond proxy + +Using a command like this: + +``` +game7ctl core inventory-gogogo --network --admin-terminus-address --admin-terminus-pool-id --sender --subject-erc721-address +``` + diff --git a/brownie-config.yaml b/brownie-config.yaml index 894ad5b..c34d7ce 100644 --- a/brownie-config.yaml +++ b/brownie-config.yaml @@ -1,5 +1,7 @@ +dotenv: .env + dependencies: - - "OpenZeppelin/openzeppelin-contracts@4.3.2" + - "OpenZeppelin/openzeppelin-contracts@4.4.0" - "bugout-dev/dao@0.0.7" - "bugout-dev/engine@0.0.3" diff --git a/contracts/diamond/Diamond.sol b/contracts/diamond/Diamond.sol index 0167022..285f2b9 100644 --- a/contracts/diamond/Diamond.sol +++ b/contracts/diamond/Diamond.sol @@ -4,10 +4,11 @@ pragma solidity ^0.8.0; // Adapted from the Diamond 3 reference implementation by Nick Mudge: // https://github.com/mudgen/diamond-3-hardhat -import {LibDiamond} from "./libraries/LibDiamond.sol"; -import {IDiamondCut} from "./interfaces/IDiamondCut.sol"; +import {LibDiamond} from "../libraries/LibDiamond.sol"; +import {IDiamondCut} from "../interfaces/IDiamondCut.sol"; +import {IDiamond} from "../interfaces/IDiamond.sol"; -contract Diamond { +contract Diamond is IDiamond { constructor(address _contractOwner, address _diamondCutFacet) payable { LibDiamond.setContractOwner(_contractOwner); diff --git a/contracts/diamond/facets/DiamondCutFacet.sol b/contracts/facets/DiamondCutFacet.sol similarity index 100% rename from contracts/diamond/facets/DiamondCutFacet.sol rename to contracts/facets/DiamondCutFacet.sol diff --git a/contracts/diamond/facets/DiamondLoupeFacet.sol b/contracts/facets/DiamondLoupeFacet.sol similarity index 100% rename from contracts/diamond/facets/DiamondLoupeFacet.sol rename to contracts/facets/DiamondLoupeFacet.sol diff --git a/contracts/inventory/Inventory.sol b/contracts/facets/InventoryFacet.sol similarity index 77% rename from contracts/inventory/Inventory.sol rename to contracts/facets/InventoryFacet.sol index 46a2ee6..aaf2af6 100644 --- a/contracts/inventory/Inventory.sol +++ b/contracts/facets/InventoryFacet.sol @@ -14,68 +14,9 @@ import "@openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol"; import "@openzeppelin-contracts/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol"; -import "../diamond/libraries/LibDiamond.sol"; - -/** -LibInventory defines the storage structure used by the Inventory contract as a facet for an EIP-2535 Diamond -proxy. - */ -library LibInventory { - bytes32 constant STORAGE_POSITION = - keccak256("g7dao.eth.storage.Inventory"); - - uint256 constant ERC20_ITEM_TYPE = 20; - uint256 constant ERC721_ITEM_TYPE = 721; - uint256 constant ERC1155_ITEM_TYPE = 1155; - - // EquippedItem represents an item equipped in a specific inventory slot for a specific ERC721 token. - struct EquippedItem { - uint256 ItemType; - address ItemAddress; - uint256 ItemTokenId; - uint256 Amount; - } - - struct InventoryStorage { - address AdminTerminusAddress; - uint256 AdminTerminusPoolId; - address SubjectERC721Address; - uint256 NumSlots; - // Slot => true if items can be unequipped from that slot and false otherwise - mapping(uint256 => bool) SlotIsUnequippable; - // Slot => item type => item address => item pool ID => maximum equippable - // For ERC20 and ERC721 tokens, item pool ID is assumed to be 0. No data will be stored under positive - // item pool IDs. - // - // NOTE: It is possible for the same contract to implement multiple of these ERCs (e.g. ERC20 and ERC721), - // so this data structure actually makes sense. - mapping(uint256 => mapping(uint256 => mapping(address => mapping(uint256 => uint256)))) SlotEligibleItems; - // Subject contract address => subject token ID => slot => EquippedItem - // Item type and Pool ID on EquippedItem have the same constraints as they do elsewhere (e.g. in SlotEligibleItems). - // - // NOTE: We have added the subject contract address as the first mapping key as a defense against - // future modifications which may allow administrators to modify the subject contract address. - // If such a modification were made, it could make it possible for a bad actor administrator - // to change the address of the subject token to the address to an ERC721 contract they control - // and drain all items from every subject token's inventory. - // If this contract is deployed as a Diamond proxy, the owner of the Diamond can pretty much - // do whatever they want in any case, but adding the subject contract address as a key protects - // users of non-Diamond deployments even under small variants of the current implementation. - // It also offers *some* protection to users of Diamond deployments of the Inventory. - mapping(address => mapping(uint256 => mapping(uint256 => EquippedItem))) EquippedItems; - } - - function inventoryStorage() - internal - pure - returns (InventoryStorage storage istore) - { - bytes32 position = STORAGE_POSITION; - assembly { - istore.slot := position - } - } -} +import "../libraries/LibDiamond.sol"; +import "../libraries/LibInventory.sol"; +import "../interfaces/IInventory.sol"; /** InventoryFacet is a smart contract that can either be used standalone or as part of an EIP-2535 Diamond @@ -92,9 +33,9 @@ Admin flow: - [x] Define tokens as equippable in inventory slots Player flow: -- [ ] Equip ERC20 tokens in eligible inventory slots -- [ ] Equip ERC721 tokens in eligible inventory slots -- [ ] Equip ERC1155 tokens in eligible inventory slots +- [] Equip ERC20 tokens in eligible inventory slots +- [] Equip ERC721 tokens in eligible inventory slots +- [] Equip ERC1155 tokens in eligible inventory slots - [ ] Unequip items from unequippable slots Batch endpoints: @@ -103,6 +44,7 @@ Batch endpoints: - [ ] Unequipping items */ contract InventoryFacet is + IInventory, ERC721Holder, ERC1155Holder, TerminusPermissions, @@ -132,43 +74,6 @@ contract InventoryFacet is _; } - event AdministratorDesignated( - address indexed adminTerminusAddress, - uint256 indexed adminTerminusPoolId - ); - - event SubjectDesignated(address indexed subjectAddress); - - event SlotCreated(address indexed creator, uint256 slot, bool unequippable); - - event ItemMarkedAsEquippableInSlot( - uint256 indexed slot, - uint256 indexed itemType, - address indexed itemAddress, - uint256 itemPoolId, - uint256 maxAmount - ); - - event ItemEquipped( - uint256 indexed subjectTokenId, - uint256 indexed slot, - uint256 itemType, - address indexed itemAddress, - uint256 itemTokenId, - uint256 amount, - address equippedBy - ); - - event ItemUnequipped( - uint256 indexed subjectTokenId, - uint256 indexed slot, - uint256 itemType, - address indexed itemAddress, - uint256 itemTokenId, - uint256 amount, - address unequippedBy - ); - /** An Inventory must be initialized with: 1. adminTerminusAddress: The address for the Terminus contract which hosts the Administrator badge. diff --git a/contracts/diamond/facets/OwnershipFacet.sol b/contracts/facets/OwnershipFacet.sol similarity index 100% rename from contracts/diamond/facets/OwnershipFacet.sol rename to contracts/facets/OwnershipFacet.sol diff --git a/contracts/interfaces/IDiamond.sol b/contracts/interfaces/IDiamond.sol new file mode 100644 index 0000000..bb1fd45 --- /dev/null +++ b/contracts/interfaces/IDiamond.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IDiamond { + fallback() external payable; + + receive() external payable; +} \ No newline at end of file diff --git a/contracts/diamond/interfaces/IDiamondCut.sol b/contracts/interfaces/IDiamondCut.sol similarity index 100% rename from contracts/diamond/interfaces/IDiamondCut.sol rename to contracts/interfaces/IDiamondCut.sol diff --git a/contracts/diamond/interfaces/IDiamondLoupe.sol b/contracts/interfaces/IDiamondLoupe.sol similarity index 100% rename from contracts/diamond/interfaces/IDiamondLoupe.sol rename to contracts/interfaces/IDiamondLoupe.sol diff --git a/contracts/diamond/interfaces/IERC165.sol b/contracts/interfaces/IERC165.sol similarity index 100% rename from contracts/diamond/interfaces/IERC165.sol rename to contracts/interfaces/IERC165.sol diff --git a/contracts/diamond/interfaces/IERC173.sol b/contracts/interfaces/IERC173.sol similarity index 89% rename from contracts/diamond/interfaces/IERC173.sol rename to contracts/interfaces/IERC173.sol index 90b73cc..20ca767 100644 --- a/contracts/diamond/interfaces/IERC173.sol +++ b/contracts/interfaces/IERC173.sol @@ -2,8 +2,6 @@ pragma solidity ^0.8.0; /// @title ERC-173 Contract Ownership Standard -/// Note: the ERC-165 identifier for this interface is 0x7f5828d0 -/* is ERC165 */ interface IERC173 { /// @dev This emits when ownership of a contract changes. event OwnershipTransferred( diff --git a/contracts/interfaces/IInventory.sol b/contracts/interfaces/IInventory.sol new file mode 100644 index 0000000..eb36b4b --- /dev/null +++ b/contracts/interfaces/IInventory.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../libraries/LibInventory.sol"; + + +interface IInventory { + + event AdministratorDesignated( + address indexed adminTerminusAddress, + uint256 indexed adminTerminusPoolId + ); + + event SubjectDesignated(address indexed subjectAddress); + + event SlotCreated(address indexed creator, uint256 slot, bool unequippable); + + event ItemMarkedAsEquippableInSlot( + uint256 indexed slot, + uint256 indexed itemType, + address indexed itemAddress, + uint256 itemPoolId, + uint256 maxAmount + ); + + event ItemEquipped( + uint256 indexed subjectTokenId, + uint256 indexed slot, + uint256 itemType, + address indexed itemAddress, + uint256 itemTokenId, + uint256 amount, + address equippedBy + ); + + event ItemUnequipped( + uint256 indexed subjectTokenId, + uint256 indexed slot, + uint256 itemType, + address indexed itemAddress, + uint256 itemTokenId, + uint256 amount, + address unequippedBy + ); + + function init( + address adminTerminusAddress, + uint256 adminTerminusPoolId, + address subjectAddress + ) external; + + function adminTerminusInfo() external view returns (address, uint256); + + function subject() external view returns (address); + + function createSlot(bool unequippable) + external returns (uint256); + + function numSlots() external view returns (uint256); + + function slotIsUnequippable(uint256 slot) external view returns (bool); + + function markItemAsEquippableInSlot( + uint256 slot, + uint256 itemType, + address itemAddress, + uint256 itemPoolId, + uint256 maxAmount + ) external; + + function maxAmountOfItemInSlot( + uint256 slot, + uint256 itemType, + address itemAddress, + uint256 itemPoolId + ) external view returns (uint256); + + function equip( + uint256 subjectTokenId, + uint256 slot, + uint256 itemType, + address itemAddress, + uint256 itemTokenId, + uint256 amount + ) external; + + function unequip( + uint256 subjectTokenId, + uint256 slot, + bool unequipAll, + uint256 amount + ) external; + + function equipped(uint256 subjectTokenId, uint256 slot) + external + view + returns (LibInventory.EquippedItem memory item); +} \ No newline at end of file diff --git a/contracts/diamond/libraries/LibDiamond.sol b/contracts/libraries/LibDiamond.sol similarity index 100% rename from contracts/diamond/libraries/LibDiamond.sol rename to contracts/libraries/LibDiamond.sol diff --git a/contracts/libraries/LibInventory.sol b/contracts/libraries/LibInventory.sol new file mode 100644 index 0000000..700754e --- /dev/null +++ b/contracts/libraries/LibInventory.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/** +LibInventory defines the storage structure used by the Inventory contract as a facet for an EIP-2535 Diamond +proxy. + */ +library LibInventory { + bytes32 constant STORAGE_POSITION = + keccak256("g7dao.eth.storage.Inventory"); + + uint256 constant ERC20_ITEM_TYPE = 20; + uint256 constant ERC721_ITEM_TYPE = 721; + uint256 constant ERC1155_ITEM_TYPE = 1155; + + // EquippedItem represents an item equipped in a specific inventory slot for a specific ERC721 token. + struct EquippedItem { + uint256 ItemType; + address ItemAddress; + uint256 ItemTokenId; + uint256 Amount; + } + + struct InventoryStorage { + address AdminTerminusAddress; + uint256 AdminTerminusPoolId; + address SubjectERC721Address; + uint256 NumSlots; + // Slot => true if items can be unequipped from that slot and false otherwise + mapping(uint256 => bool) SlotIsUnequippable; + // Slot => item type => item address => item pool ID => maximum equippable + // For ERC20 and ERC721 tokens, item pool ID is assumed to be 0. No data will be stored under positive + // item pool IDs. + // + // NOTE: It is possible for the same contract to implement multiple of these ERCs (e.g. ERC20 and ERC721), + // so this data structure actually makes sense. + mapping(uint256 => mapping(uint256 => mapping(address => mapping(uint256 => uint256)))) SlotEligibleItems; + // Subject contract address => subject token ID => slot => EquippedItem + // Item type and Pool ID on EquippedItem have the same constraints as they do elsewhere (e.g. in SlotEligibleItems). + // + // NOTE: We have added the subject contract address as the first mapping key as a defense against + // future modifications which may allow administrators to modify the subject contract address. + // If such a modification were made, it could make it possible for a bad actor administrator + // to change the address of the subject token to the address to an ERC721 contract they control + // and drain all items from every subject token's inventory. + // If this contract is deployed as a Diamond proxy, the owner of the Diamond can pretty much + // do whatever they want in any case, but adding the subject contract address as a key protects + // users of non-Diamond deployments even under small variants of the current implementation. + // It also offers *some* protection to users of Diamond deployments of the Inventory. + // ERC721 => + // subjectTokenId => + // slotId => + // EquippedItem struct + mapping(address => mapping(uint256 => mapping(uint256 => EquippedItem))) EquippedItems; + } + + function inventoryStorage() + internal + pure + returns (InventoryStorage storage istore) + { + bytes32 position = STORAGE_POSITION; + assembly { + istore.slot := position + } + } +} \ No newline at end of file diff --git a/contracts/mock/ShibaERC721.sol b/contracts/mock/ShibaERC721.sol new file mode 100644 index 0000000..b189d72 --- /dev/null +++ b/contracts/mock/ShibaERC721.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import "@openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; +import "@openzeppelin-contracts/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin-contracts/contracts/access/Ownable.sol"; +import "@openzeppelin-contracts/contracts/utils/Counters.sol"; + +contract ShibaERC721 is ERC721, ERC721URIStorage, Ownable { + using Counters for Counters.Counter; + Counters.Counter private _tokenIdCounter; + + constructor() ERC721("MyShibaToken", "SHIBA") {} + + function safeMint(address to, string memory uri) public onlyOwner { + uint tokenId = _tokenIdCounter.current(); + _tokenIdCounter.increment(); + _safeMint(to, tokenId); + _setTokenURI(tokenId, uri); + } + + function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) { + super._burn(tokenId); + } + + function tokenURI(uint256 tokenId) + public + view + override(ERC721, ERC721URIStorage) + returns (string memory) + { + return super.tokenURI(tokenId); + } +} diff --git a/scripts/deploy_shiba_erc721.py b/scripts/deploy_shiba_erc721.py new file mode 100644 index 0000000..9e12ab3 --- /dev/null +++ b/scripts/deploy_shiba_erc721.py @@ -0,0 +1,10 @@ +from brownie import ShibaERC721, accounts, network, config + +def main(): + dev = accounts.load('deployment_account') + + shiba = ShibaERC721.deploy( + {"from": dev}, + publish_source=True + ) + return shiba diff --git a/scripts/mint_shiba_nft.py b/scripts/mint_shiba_nft.py new file mode 100644 index 0000000..d5ea94a --- /dev/null +++ b/scripts/mint_shiba_nft.py @@ -0,0 +1,13 @@ +# mint 1 shiba nft using brownie with the smart contract + +from brownie import ShibaERC721, accounts, network + +def main(): + dev = accounts.load('deployment_account') + print(network.show_active()) + shiba_nft = ShibaERC721[len(ShibaERC721) - 1] + shiba_nft.tokenCounter() + transaction = shiba_nft.safeMint("0xa2F5785506b0344abFD15EEFc4BDe21D4cD3125b", "https://gateway.pinata.cloud/ipfs/QmTVkd2oDF5Wnf8ZTntvyU5izfjbfvLPbnWDtjsAvfY1y3", {"from": dev}) + transaction.wait(1) + # show the nft on polygon mumbai scan + print("https://mumbai.polygonscan.com/tx/" + transaction.txid) From 8862ae045c0aae7cbf432f04187df608ee786fd2 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Thu, 19 Jan 2023 08:17:38 -0300 Subject: [PATCH 02/14] feature(Inventory): adding slotdata x subjecttokenid --- contracts/facets/InventoryFacet.sol | 115 +++++++++++++++++++++++---- contracts/interfaces/IInventory.sol | 26 +++++- contracts/libraries/LibInventory.sol | 44 ++++++++-- contracts/mock/MockERC1155.sol | 2 +- scripts/mint_shiba_nft.py | 5 +- 5 files changed, 163 insertions(+), 29 deletions(-) diff --git a/contracts/facets/InventoryFacet.sol b/contracts/facets/InventoryFacet.sol index aaf2af6..14c834c 100644 --- a/contracts/facets/InventoryFacet.sol +++ b/contracts/facets/InventoryFacet.sol @@ -64,6 +64,18 @@ contract InventoryFacet is _; } + // TODO: @ogarciarevett finish this + // modifier onlySlotOwner(uint256 slotId) { + // // LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); + + // // // TODO: @ogarciarevett check if asking for the msg.sender will be required, if the user change the wallet could loose this relation + // // istore.SubjectSlots[msg.sender] + + // // require(msg.sender); + + // _; + // } + modifier requireValidItemType(uint256 itemType) { require( itemType == LibInventory.ERC20_ITEM_TYPE || @@ -78,22 +90,22 @@ contract InventoryFacet is An Inventory must be initialized with: 1. adminTerminusAddress: The address for the Terminus contract which hosts the Administrator badge. 2. adminTerminusPoolId: The pool ID for the Administrator badge on that Terminus contract. - 3. subjectAddress: The address of the ERC721 contract that the Inventory refers to. + 3. contractAddress: The address of the ERC721 contract that the Inventory refers to. */ function init( address adminTerminusAddress, uint256 adminTerminusPoolId, - address subjectAddress + address contractAddress ) external { LibDiamond.enforceIsContractOwner(); LibInventory.InventoryStorage storage istore = LibInventory .inventoryStorage(); istore.AdminTerminusAddress = adminTerminusAddress; istore.AdminTerminusPoolId = adminTerminusPoolId; - istore.SubjectERC721Address = subjectAddress; + istore.ContractERC721Address = contractAddress; emit AdministratorDesignated(adminTerminusAddress, adminTerminusPoolId); - emit SubjectDesignated(subjectAddress); + emit ContractAddressDesignated(contractAddress); } function adminTerminusInfo() external view returns (address, uint256) { @@ -103,34 +115,105 @@ contract InventoryFacet is } function subject() external view returns (address) { - return LibInventory.inventoryStorage().SubjectERC721Address; + return LibInventory.inventoryStorage().ContractERC721Address; } - function createSlot(bool unequippable) + function createSlot( + bool unequippable, + uint256 slotType, + string memory slotURI + ) external onlyAdmin returns (uint256) { + require(slotType <= uint(LibInventory.SlotType.Trophies) && slotType >= uint(LibInventory.SlotType.Clothes)); + LibInventory.InventoryStorage storage istore = LibInventory .inventoryStorage(); // Slots are 1-indexed! istore.NumSlots += 1; uint256 newSlot = istore.NumSlots; + + // TODO: @ogarciarevett remove this, is already in the Slot struct istore.SlotIsUnequippable[newSlot] = unequippable; + + // save the slot type! + istore.SlotData[newSlot] = LibInventory.Slot({ + slotType: LibInventory.SlotType(slotType), + SlotURI: slotURI, + SlotIsUnequippable: unequippable, + SlotId: newSlot + }); emit SlotCreated(msg.sender, newSlot, unequippable); return newSlot; } + function assignSlotToSubjectTokenId(uint256 toSubjectTokenId, uint256 slotId) external onlyAdmin { + LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); + + LibInventory.Slot memory slotData = istore.SlotData[slotId]; + + istore.SubjectSlots[istore.ContractERC721Address][toSubjectTokenId].push(slotData); + + emit AssignSlotToSubjectTokenId( + toSubjectTokenId, + slotId + ); + } + + function getSubjectTokenSlots(uint256 subjectTokenId) external view returns(LibInventory.Slot[] memory slots) { + LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); + IERC721 subjectContract = IERC721(istore.ContractERC721Address); + require( + msg.sender == subjectContract.ownerOf(subjectTokenId), + "InventoryFacet.getSubjectTokenSlots: Message sender is not owner of subject token" + ); + return istore.SubjectSlots[istore.ContractERC721Address][subjectTokenId]; + } + + // COUNTER function numSlots() external view returns (uint256) { return LibInventory.inventoryStorage().NumSlots; } - function slotIsUnequippable(uint256 slot) external view returns (bool) { - return LibInventory.inventoryStorage().SlotIsUnequippable[slot]; + function getSlotById(uint256 subjectTokenId, uint slotId) + external + view + // @TODO: @ogarciarevett add slotOwner modifier + returns (LibInventory.Slot memory slot) { + + return LibInventory.inventoryStorage().SlotData[slotId]; + } + + function getSlotURI(uint256 slotId) external view returns (string memory) { + LibInventory.InventoryStorage storage istore = LibInventory + .inventoryStorage(); + + return istore.SlotData[slotId].SlotURI; + } + + // @TODO: @ogarciarevett add slotOwner modifier + function setSlotUri(string memory newSlotURI, uint slotId) external diamondNonReentrant { + LibInventory.InventoryStorage storage istore = LibInventory + .inventoryStorage(); + + LibInventory.Slot memory slot = istore.SlotData[slotId]; + slot.SlotURI = newSlotURI; + emit NewSlotURI(slotId); + } + + function slotIsUnequippable(uint256 slotId) external view returns (bool) { + return LibInventory.inventoryStorage().SlotData[slotId].SlotIsUnequippable; } + // TODO: @ogarciarevett remove this, is already in the Slot struct + // function _slotIsUnequippable(uint256 slot) external view returns (bool) { + // return LibInventory.inventoryStorage().SlotIsUnequippable[slot]; + // } + function markItemAsEquippableInSlot( uint256 slot, uint256 itemType, @@ -205,7 +288,7 @@ contract InventoryFacet is ); LibInventory.EquippedItem storage existingItem = istore.EquippedItems[ - istore.SubjectERC721Address + istore.ContractERC721Address ][subjectTokenId][slot]; if (unequipAll) { @@ -254,7 +337,7 @@ contract InventoryFacet is existingItem.Amount -= amount; if (existingItem.Amount == 0) { - delete istore.EquippedItems[istore.SubjectERC721Address][ + delete istore.EquippedItems[istore.ContractERC721Address][ subjectTokenId ][slot]; } @@ -284,7 +367,7 @@ contract InventoryFacet is LibInventory.InventoryStorage storage istore = LibInventory .inventoryStorage(); - IERC721 subjectContract = IERC721(istore.SubjectERC721Address); + IERC721 subjectContract = IERC721(istore.ContractERC721Address); require( msg.sender == subjectContract.ownerOf(subjectTokenId), "InventoryFacet.equip: Message sender is not owner of subject token" @@ -296,7 +379,7 @@ contract InventoryFacet is // between the existing amount of the token and the target amount. if ( istore - .EquippedItems[istore.SubjectERC721Address][subjectTokenId][slot] + .EquippedItems[istore.ContractERC721Address][subjectTokenId][slot] .ItemType != 0 ) { _unequip(subjectTokenId, slot, true, 0); @@ -361,7 +444,7 @@ contract InventoryFacet is msg.sender ); - istore.EquippedItems[istore.SubjectERC721Address][subjectTokenId][ + istore.EquippedItems[istore.ContractERC721Address][subjectTokenId][ slot ] = LibInventory.EquippedItem({ ItemType: itemType, @@ -380,7 +463,7 @@ contract InventoryFacet is LibInventory.InventoryStorage storage istore = LibInventory .inventoryStorage(); - IERC721 subjectContract = IERC721(istore.SubjectERC721Address); + IERC721 subjectContract = IERC721(istore.ContractERC721Address); require( msg.sender == subjectContract.ownerOf(subjectTokenId), "InventoryFacet.equip: Message sender is not owner of subject token" @@ -389,7 +472,7 @@ contract InventoryFacet is _unequip(subjectTokenId, slot, unequipAll, amount); } - function equipped(uint256 subjectTokenId, uint256 slot) + function getEquippedItems(uint256 subjectTokenId, uint256 slot) external view returns (LibInventory.EquippedItem memory item) @@ -398,7 +481,7 @@ contract InventoryFacet is .inventoryStorage(); LibInventory.EquippedItem memory equippedItem = istore.EquippedItems[ - istore.SubjectERC721Address + istore.ContractERC721Address ][subjectTokenId][slot]; return equippedItem; diff --git a/contracts/interfaces/IInventory.sol b/contracts/interfaces/IInventory.sol index eb36b4b..b64def1 100644 --- a/contracts/interfaces/IInventory.sol +++ b/contracts/interfaces/IInventory.sol @@ -11,7 +11,7 @@ interface IInventory { uint256 indexed adminTerminusPoolId ); - event SubjectDesignated(address indexed subjectAddress); + event ContractAddressDesignated(address indexed contractAddress); event SlotCreated(address indexed creator, uint256 slot, bool unequippable); @@ -23,6 +23,10 @@ interface IInventory { uint256 maxAmount ); + event AssignSlotToSubjectTokenId(uint indexed toSubjectTokenId, uint256 indexed slotId); + + event NewSlotURI(uint indexed slotId); + event ItemEquipped( uint256 indexed subjectTokenId, uint256 indexed slot, @@ -53,12 +57,12 @@ interface IInventory { function subject() external view returns (address); - function createSlot(bool unequippable) + function createSlot(bool unequippable, uint256 slotType, string memory slotURI) external returns (uint256); function numSlots() external view returns (uint256); - function slotIsUnequippable(uint256 slot) external view returns (bool); + function slotIsUnequippable(uint256 slotId) external view returns (bool); function markItemAsEquippableInSlot( uint256 slot, @@ -91,8 +95,22 @@ interface IInventory { uint256 amount ) external; - function equipped(uint256 subjectTokenId, uint256 slot) + function getEquippedItems(uint256 subjectTokenId, uint256 slot) external view returns (LibInventory.EquippedItem memory item); + + function getSlotById(uint256 subjectTokenId, uint slotId) + external + view + returns (LibInventory.Slot memory slots); + + function getSubjectTokenSlots(uint256 subjectTokenId) + external + view + returns(LibInventory.Slot[] memory slot); + + function assignSlotToSubjectTokenId(uint256 toSubjectTokenId, uint256 slotId) external; + + function getSlotURI(uint256 slotId) external view returns (string memory); } \ No newline at end of file diff --git a/contracts/libraries/LibInventory.sol b/contracts/libraries/LibInventory.sol index 700754e..9202c45 100644 --- a/contracts/libraries/LibInventory.sol +++ b/contracts/libraries/LibInventory.sol @@ -13,6 +13,27 @@ library LibInventory { uint256 constant ERC721_ITEM_TYPE = 721; uint256 constant ERC1155_ITEM_TYPE = 1155; + // Returns uint + // Clothes - 0 + // Accesories - 1 + // Materials - 2 + // Badges - 3 + // Trophies - 4 + enum SlotType { + Clothes, + Accesories, + Materials, + Badges, + Trophies + } + + struct Slot { + string SlotURI; + SlotType slotType; + bool SlotIsUnequippable; + uint256 SlotId; + } + // EquippedItem represents an item equipped in a specific inventory slot for a specific ERC721 token. struct EquippedItem { uint256 ItemType; @@ -24,10 +45,17 @@ library LibInventory { struct InventoryStorage { address AdminTerminusAddress; uint256 AdminTerminusPoolId; - address SubjectERC721Address; + address ContractERC721Address; uint256 NumSlots; + + // TODO: @ogarciarevett remove this, is already in the Slot struct // Slot => true if items can be unequipped from that slot and false otherwise mapping(uint256 => bool) SlotIsUnequippable; + + // SlotId => slot, useful to get the rest of the slot data. + mapping(uint256 => Slot) SlotData; + + // Slot => item type => item address => item pool ID => maximum equippable // For ERC20 and ERC721 tokens, item pool ID is assumed to be 0. No data will be stored under positive // item pool IDs. @@ -35,6 +63,7 @@ library LibInventory { // NOTE: It is possible for the same contract to implement multiple of these ERCs (e.g. ERC20 and ERC721), // so this data structure actually makes sense. mapping(uint256 => mapping(uint256 => mapping(address => mapping(uint256 => uint256)))) SlotEligibleItems; + // Subject contract address => subject token ID => slot => EquippedItem // Item type and Pool ID on EquippedItem have the same constraints as they do elsewhere (e.g. in SlotEligibleItems). // @@ -47,11 +76,16 @@ library LibInventory { // do whatever they want in any case, but adding the subject contract address as a key protects // users of non-Diamond deployments even under small variants of the current implementation. // It also offers *some* protection to users of Diamond deployments of the Inventory. - // ERC721 => - // subjectTokenId => - // slotId => - // EquippedItem struct + // ERC721 Contract Address => + // subjectTokenId => + // slotId => + // EquippedItem struct mapping(address => mapping(uint256 => mapping(uint256 => EquippedItem))) EquippedItems; + + // ERC721 Contract Address => + // subjectTokenId => + // slots + mapping(address => mapping(uint256 => Slot[])) SubjectSlots; } function inventoryStorage() diff --git a/contracts/mock/MockERC1155.sol b/contracts/mock/MockERC1155.sol index dbee792..f14c7cb 100644 --- a/contracts/mock/MockERC1155.sol +++ b/contracts/mock/MockERC1155.sol @@ -5,7 +5,7 @@ pragma solidity ^0.8.0; import "@openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol"; contract MockERC1155 is ERC1155Burnable { - constructor() ERC1155("lol://lol") {} + constructor() ERC1155("lol://lol/{id}") {} function mint( address to, diff --git a/scripts/mint_shiba_nft.py b/scripts/mint_shiba_nft.py index d5ea94a..d3ccfe2 100644 --- a/scripts/mint_shiba_nft.py +++ b/scripts/mint_shiba_nft.py @@ -6,8 +6,7 @@ def main(): dev = accounts.load('deployment_account') print(network.show_active()) shiba_nft = ShibaERC721[len(ShibaERC721) - 1] - shiba_nft.tokenCounter() - transaction = shiba_nft.safeMint("0xa2F5785506b0344abFD15EEFc4BDe21D4cD3125b", "https://gateway.pinata.cloud/ipfs/QmTVkd2oDF5Wnf8ZTntvyU5izfjbfvLPbnWDtjsAvfY1y3", {"from": dev}) + transaction = shiba_nft.safeMint("ADDRESS_HERE", "URI_HERE", {"from": dev}) transaction.wait(1) - # show the nft on polygon mumbai scan + # show the nft on polygon mumbai scan, var env $POLYGONSCAN_TOKEN required print("https://mumbai.polygonscan.com/tx/" + transaction.txid) From ee4ba8570f5eb8da0828c1172e4742550693e1cf Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Thu, 19 Jan 2023 08:24:06 -0300 Subject: [PATCH 03/14] wip(docs): going back to the current cli-name into theREADME.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2d5ab66..37ba58a 100644 --- a/README.md +++ b/README.md @@ -63,13 +63,13 @@ moonworm generate-brownie -p . -o game7ctl/game7ctl -n InventoryFacet ### `game7ctl` Once you have set up `game7ctl`, you can use it to deploy the contracts in this repository. For example, -to deploy the Inventory contract as a Diamond proxy, you would use the `game7ctl core inventory-facet-deploy` command. +to deploy the Inventory contract as a Diamond proxy, you would use the `game7ctl core inventory-gogogo` command. To see all the parameters you can pass in the deployment, run: ``` -$ game7ctl core inventory-facet-deploy --help -usage: game7ctl inventory-facet-deploy [-h] --network NETWORK [--address ADDRESS] --sender SENDER [--password PASSWORD] [--gas-price GAS_PRICE] [--max-fee-per-gas MAX_FEE_PER_GAS] +$ game7ctl core inventory-gogogo --help +usage: game7ctl inventory-gogogo [-h] --network NETWORK [--address ADDRESS] --sender SENDER [--password PASSWORD] [--gas-price GAS_PRICE] [--max-fee-per-gas MAX_FEE_PER_GAS] [--max-priority-fee-per-gas MAX_PRIORITY_FEE_PER_GAS] [--confirmations CONFIRMATIONS] [--nonce NONCE] [--value VALUE] [--verbose] --admin-terminus-address ADMIN_TERMINUS_ADDRESS --admin-terminus-pool-id ADMIN_TERMINUS_POOL_ID --subject-erc721-address SUBJECT_ERC721_ADDRESS [--diamond-cut-address DIAMOND_CUT_ADDRESS] [--diamond-address DIAMOND_ADDRESS] [--diamond-loupe-address DIAMOND_LOUPE_ADDRESS] From 1e945e8b423d2cdfc0dbf7d4395ba16d6d07e044 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Sun, 22 Jan 2023 18:11:05 -0300 Subject: [PATCH 04/14] merge(dev): resolving README.md conflicts --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 2c528ef..faf81a3 100644 --- a/README.md +++ b/README.md @@ -56,14 +56,10 @@ For example, after modifying `InventoryFacet`, you would run: moonworm generate-brownie -p . -o game7ctl/game7ctl -n InventoryFacet ``` -<<<<<<< HEAD ---- -======= If you want to register your contract for automatic regeneration, please add it to the `IMPORTANT_CONTRACTS` array in [./game7ctl/regen.bash](`regen.bash`). - - - ->>>>>>> ded38dabaea3dc442a34ebd16a2add8f7964868d ## Deploying contracts From 3bddf72f490d99b716e5d24d4a93cb2153538b53 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Sat, 28 Jan 2023 16:57:57 -0300 Subject: [PATCH 05/14] Fix py tests with the new Slot struct --- contracts/facets/InventoryFacet.sol | 5 +- contracts/libraries/LibInventory.sol | 4 - game7ctl/game7ctl/InventoryFacet.py | 193 +++++++++++++++++++++++--- game7ctl/game7ctl/inventory_events.py | 6 +- game7ctl/game7ctl/test_inventory.py | 120 ++++++++-------- 5 files changed, 237 insertions(+), 91 deletions(-) diff --git a/contracts/facets/InventoryFacet.sol b/contracts/facets/InventoryFacet.sol index 8aa3be7..f968758 100644 --- a/contracts/facets/InventoryFacet.sol +++ b/contracts/facets/InventoryFacet.sol @@ -135,9 +135,6 @@ contract InventoryFacet is // Slots are 1-indexed! istore.NumSlots += 1; uint256 newSlot = istore.NumSlots; - - // TODO: @ogarciarevett remove this, is already in the Slot struct - istore.SlotIsUnequippable[newSlot] = unequippable; // save the slot type! istore.SlotData[newSlot] = LibInventory.Slot({ @@ -283,7 +280,7 @@ contract InventoryFacet is .inventoryStorage(); require( - istore.SlotIsUnequippable[slot], + istore.SlotData[slot].SlotIsUnequippable, "InventoryFacet._unequip: That slot is not unequippable" ); diff --git a/contracts/libraries/LibInventory.sol b/contracts/libraries/LibInventory.sol index 9202c45..9d3d3f5 100644 --- a/contracts/libraries/LibInventory.sol +++ b/contracts/libraries/LibInventory.sol @@ -48,10 +48,6 @@ library LibInventory { address ContractERC721Address; uint256 NumSlots; - // TODO: @ogarciarevett remove this, is already in the Slot struct - // Slot => true if items can be unequipped from that slot and false otherwise - mapping(uint256 => bool) SlotIsUnequippable; - // SlotId => slot, useful to get the rest of the slot data. mapping(uint256 => Slot) SlotData; diff --git a/game7ctl/game7ctl/InventoryFacet.py b/game7ctl/game7ctl/InventoryFacet.py index ea5169c..f69b93d 100644 --- a/game7ctl/game7ctl/InventoryFacet.py +++ b/game7ctl/game7ctl/InventoryFacet.py @@ -102,9 +102,21 @@ def admin_terminus_info( self.assert_contract_is_instantiated() return self.contract.adminTerminusInfo.call(block_identifier=block_number) - def create_slot(self, unequippable: bool, transaction_config) -> Any: + def assign_slot_to_subject_token_id( + self, to_subject_token_id: int, slot_id: int, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.assignSlotToSubjectTokenId( + to_subject_token_id, slot_id, transaction_config + ) + + def create_slot( + self, unequippable: bool, slot_type: int, slot_uri: str, transaction_config + ) -> Any: self.assert_contract_is_instantiated() - return self.contract.createSlot(unequippable, transaction_config) + return self.contract.createSlot( + unequippable, slot_type, slot_uri, transaction_config + ) def equip( self, @@ -127,29 +139,54 @@ def equip( transaction_config, ) - def equipped( + def get_equipped_items( self, subject_token_id: int, slot: int, block_number: Optional[Union[str, int]] = "latest", ) -> Any: self.assert_contract_is_instantiated() - return self.contract.equipped.call( + return self.contract.getEquippedItems.call( subject_token_id, slot, block_identifier=block_number ) + def get_slot_by_id( + self, + subject_token_id: int, + slot_id: int, + block_number: Optional[Union[str, int]] = "latest", + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.getSlotById.call( + subject_token_id, slot_id, block_identifier=block_number + ) + + def get_slot_uri( + self, slot_id: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.getSlotURI.call(slot_id, block_identifier=block_number) + + def get_subject_token_slots( + self, subject_token_id: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.getSubjectTokenSlots.call( + subject_token_id, block_identifier=block_number + ) + def init( self, admin_terminus_address: ChecksumAddress, admin_terminus_pool_id: int, - subject_address: ChecksumAddress, + contract_address: ChecksumAddress, transaction_config, ) -> Any: self.assert_contract_is_instantiated() return self.contract.init( admin_terminus_address, admin_terminus_pool_id, - subject_address, + contract_address, transaction_config, ) @@ -225,12 +262,16 @@ def on_erc721_received( arg1, arg2, arg3, arg4, transaction_config ) + def set_slot_uri(self, new_slot_uri: str, slot_id: int, transaction_config) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setSlotUri(new_slot_uri, slot_id, transaction_config) + def slot_is_unequippable( - self, slot: int, block_number: Optional[Union[str, int]] = "latest" + self, slot_id: int, block_number: Optional[Union[str, int]] = "latest" ) -> Any: self.assert_contract_is_instantiated() return self.contract.slotIsUnequippable.call( - slot, block_identifier=block_number + slot_id, block_identifier=block_number ) def subject(self, block_number: Optional[Union[str, int]] = "latest") -> Any: @@ -350,12 +391,29 @@ def handle_admin_terminus_info(args: argparse.Namespace) -> None: print(result) +def handle_assign_slot_to_subject_token_id(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = InventoryFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.assign_slot_to_subject_token_id( + to_subject_token_id=args.to_subject_token_id, + slot_id=args.slot_id, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + def handle_create_slot(args: argparse.Namespace) -> None: network.connect(args.network) contract = InventoryFacet(args.address) transaction_config = get_transaction_config(args) result = contract.create_slot( - unequippable=args.unequippable, transaction_config=transaction_config + unequippable=args.unequippable, + slot_type=args.slot_type, + slot_uri=args.slot_uri, + transaction_config=transaction_config, ) print(result) if args.verbose: @@ -380,10 +438,10 @@ def handle_equip(args: argparse.Namespace) -> None: print(result.info()) -def handle_equipped(args: argparse.Namespace) -> None: +def handle_get_equipped_items(args: argparse.Namespace) -> None: network.connect(args.network) contract = InventoryFacet(args.address) - result = contract.equipped( + result = contract.get_equipped_items( subject_token_id=args.subject_token_id, slot=args.slot, block_number=args.block_number, @@ -391,6 +449,33 @@ def handle_equipped(args: argparse.Namespace) -> None: print(result) +def handle_get_slot_by_id(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = InventoryFacet(args.address) + result = contract.get_slot_by_id( + subject_token_id=args.subject_token_id, + slot_id=args.slot_id, + block_number=args.block_number, + ) + print(result) + + +def handle_get_slot_uri(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = InventoryFacet(args.address) + result = contract.get_slot_uri(slot_id=args.slot_id, block_number=args.block_number) + print(result) + + +def handle_get_subject_token_slots(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = InventoryFacet(args.address) + result = contract.get_subject_token_slots( + subject_token_id=args.subject_token_id, block_number=args.block_number + ) + print(result) + + def handle_init(args: argparse.Namespace) -> None: network.connect(args.network) contract = InventoryFacet(args.address) @@ -398,7 +483,7 @@ def handle_init(args: argparse.Namespace) -> None: result = contract.init( admin_terminus_address=args.admin_terminus_address, admin_terminus_pool_id=args.admin_terminus_pool_id, - subject_address=args.subject_address, + contract_address=args.contract_address, transaction_config=transaction_config, ) print(result) @@ -493,11 +578,25 @@ def handle_on_erc721_received(args: argparse.Namespace) -> None: print(result.info()) +def handle_set_slot_uri(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = InventoryFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_slot_uri( + new_slot_uri=args.new_slot_uri, + slot_id=args.slot_id, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + def handle_slot_is_unequippable(args: argparse.Namespace) -> None: network.connect(args.network) contract = InventoryFacet(args.address) result = contract.slot_is_unequippable( - slot=args.slot, block_number=args.block_number + slot_id=args.slot_id, block_number=args.block_number ) print(result) @@ -551,11 +650,31 @@ def generate_cli() -> argparse.ArgumentParser: add_default_arguments(admin_terminus_info_parser, False) admin_terminus_info_parser.set_defaults(func=handle_admin_terminus_info) + assign_slot_to_subject_token_id_parser = subcommands.add_parser( + "assign-slot-to-subject-token-id" + ) + add_default_arguments(assign_slot_to_subject_token_id_parser, True) + assign_slot_to_subject_token_id_parser.add_argument( + "--to-subject-token-id", required=True, help="Type: uint256", type=int + ) + assign_slot_to_subject_token_id_parser.add_argument( + "--slot-id", required=True, help="Type: uint256", type=int + ) + assign_slot_to_subject_token_id_parser.set_defaults( + func=handle_assign_slot_to_subject_token_id + ) + create_slot_parser = subcommands.add_parser("create-slot") add_default_arguments(create_slot_parser, True) create_slot_parser.add_argument( "--unequippable", required=True, help="Type: bool", type=boolean_argument_type ) + create_slot_parser.add_argument( + "--slot-type", required=True, help="Type: uint256", type=int + ) + create_slot_parser.add_argument( + "--slot-uri", required=True, help="Type: string", type=str + ) create_slot_parser.set_defaults(func=handle_create_slot) equip_parser = subcommands.add_parser("equip") @@ -574,15 +693,39 @@ def generate_cli() -> argparse.ArgumentParser: equip_parser.add_argument("--amount", required=True, help="Type: uint256", type=int) equip_parser.set_defaults(func=handle_equip) - equipped_parser = subcommands.add_parser("equipped") - add_default_arguments(equipped_parser, False) - equipped_parser.add_argument( + get_equipped_items_parser = subcommands.add_parser("get-equipped-items") + add_default_arguments(get_equipped_items_parser, False) + get_equipped_items_parser.add_argument( "--subject-token-id", required=True, help="Type: uint256", type=int ) - equipped_parser.add_argument( + get_equipped_items_parser.add_argument( "--slot", required=True, help="Type: uint256", type=int ) - equipped_parser.set_defaults(func=handle_equipped) + get_equipped_items_parser.set_defaults(func=handle_get_equipped_items) + + get_slot_by_id_parser = subcommands.add_parser("get-slot-by-id") + add_default_arguments(get_slot_by_id_parser, False) + get_slot_by_id_parser.add_argument( + "--subject-token-id", required=True, help="Type: uint256", type=int + ) + get_slot_by_id_parser.add_argument( + "--slot-id", required=True, help="Type: uint256", type=int + ) + get_slot_by_id_parser.set_defaults(func=handle_get_slot_by_id) + + get_slot_uri_parser = subcommands.add_parser("get-slot-uri") + add_default_arguments(get_slot_uri_parser, False) + get_slot_uri_parser.add_argument( + "--slot-id", required=True, help="Type: uint256", type=int + ) + get_slot_uri_parser.set_defaults(func=handle_get_slot_uri) + + get_subject_token_slots_parser = subcommands.add_parser("get-subject-token-slots") + add_default_arguments(get_subject_token_slots_parser, False) + get_subject_token_slots_parser.add_argument( + "--subject-token-id", required=True, help="Type: uint256", type=int + ) + get_subject_token_slots_parser.set_defaults(func=handle_get_subject_token_slots) init_parser = subcommands.add_parser("init") add_default_arguments(init_parser, True) @@ -592,7 +735,7 @@ def generate_cli() -> argparse.ArgumentParser: init_parser.add_argument( "--admin-terminus-pool-id", required=True, help="Type: uint256", type=int ) - init_parser.add_argument("--subject-address", required=True, help="Type: address") + init_parser.add_argument("--contract-address", required=True, help="Type: address") init_parser.set_defaults(func=handle_init) mark_item_as_equippable_in_slot_parser = subcommands.add_parser( @@ -698,10 +841,20 @@ def generate_cli() -> argparse.ArgumentParser: ) on_erc721_received_parser.set_defaults(func=handle_on_erc721_received) + set_slot_uri_parser = subcommands.add_parser("set-slot-uri") + add_default_arguments(set_slot_uri_parser, True) + set_slot_uri_parser.add_argument( + "--new-slot-uri", required=True, help="Type: string", type=str + ) + set_slot_uri_parser.add_argument( + "--slot-id", required=True, help="Type: uint256", type=int + ) + set_slot_uri_parser.set_defaults(func=handle_set_slot_uri) + slot_is_unequippable_parser = subcommands.add_parser("slot-is-unequippable") add_default_arguments(slot_is_unequippable_parser, False) slot_is_unequippable_parser.add_argument( - "--slot", required=True, help="Type: uint256", type=int + "--slot-id", required=True, help="Type: uint256", type=int ) slot_is_unequippable_parser.set_defaults(func=handle_slot_is_unequippable) diff --git a/game7ctl/game7ctl/inventory_events.py b/game7ctl/game7ctl/inventory_events.py index eefe2de..53af594 100644 --- a/game7ctl/game7ctl/inventory_events.py +++ b/game7ctl/game7ctl/inventory_events.py @@ -18,17 +18,17 @@ "type": "event", } -SUBJECT_DESIGNATED_ABI = { +CONTRACT_ADDRESS_DESIGNATED_ABI = { "anonymous": False, "inputs": [ { "indexed": True, "internalType": "address", - "name": "subjectAddress", + "name": "contractAddress", "type": "address", } ], - "name": "SubjectDesignated", + "name": "ContractAddressDesignated", "type": "event", } diff --git a/game7ctl/game7ctl/test_inventory.py b/game7ctl/game7ctl/test_inventory.py index 7cab8ef..ee33f3a 100644 --- a/game7ctl/game7ctl/test_inventory.py +++ b/game7ctl/game7ctl/test_inventory.py @@ -93,17 +93,17 @@ def test_administrator_designated_event(self): def test_subject_erc721_address(self): self.assertEqual(self.inventory.subject(), self.nft.address) - def test_subject_designated_event(self): - subject_designated_events = _fetch_events_chunk( + def test_contract_address_designated_event(self): + contract_address_designated_events = _fetch_events_chunk( web3_client, - inventory_events.SUBJECT_DESIGNATED_ABI, + inventory_events.CONTRACT_ADDRESS_DESIGNATED_ABI, self.predeployment_block, self.postdeployment_block, ) - self.assertEqual(len(subject_designated_events), 1) + self.assertEqual(len(contract_address_designated_events), 1) self.assertEqual( - subject_designated_events[0]["args"]["subjectAddress"], + contract_address_designated_events[0]["args"]["contractAddress"], self.nft.address, ) @@ -113,7 +113,7 @@ def test_admin_can_create_nonunequippable_slot(self): unequippable = False num_slots_0 = self.inventory.num_slots() - tx_receipt = self.inventory.create_slot(unequippable, {"from": self.admin}) + tx_receipt = self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) num_slots_1 = self.inventory.num_slots() self.assertEqual(num_slots_1, num_slots_0 + 1) @@ -144,7 +144,7 @@ def test_admin_can_create_unequippable_slot(self): unequippable = True num_slots_0 = self.inventory.num_slots() - tx_receipt = self.inventory.create_slot(unequippable, {"from": self.admin}) + tx_receipt = self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) num_slots_1 = self.inventory.num_slots() self.assertEqual(num_slots_1, num_slots_0 + 1) @@ -176,7 +176,7 @@ def test_nonadmin_cannot_create_slot(self): num_slots_0 = self.inventory.num_slots() with self.assertRaises(VirtualMachineError): - self.inventory.create_slot(unequippable, {"from": self.player}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.player}) num_slots_1 = self.inventory.num_slots() self.assertEqual(num_slots_1, num_slots_0) @@ -185,7 +185,7 @@ def test_admin_cannot_mark_contracts_with_invalid_type_as_eligible_for_slots( self, ): unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() invalid_type = 0 @@ -209,7 +209,7 @@ def test_admin_cannot_mark_contracts_with_invalid_type_as_eligible_for_slots( def test_admin_can_mark_erc20_tokens_as_eligible_for_slots(self): unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() erc20_type = 20 @@ -261,7 +261,7 @@ def test_admin_can_mark_erc20_tokens_as_eligible_for_slots(self): def test_nonadmin_cannot_mark_erc20_tokens_as_eligible_for_slots(self): unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() erc20_type = 20 @@ -287,7 +287,7 @@ def test_admin_cannot_mark_erc20_tokens_as_eligible_for_slots_if_pool_id_is_nonz self, ): unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() erc20_type = 20 @@ -311,7 +311,7 @@ def test_admin_cannot_mark_erc20_tokens_as_eligible_for_slots_if_pool_id_is_nonz def test_admin_can_mark_erc721_tokens_as_eligible_for_slots(self): unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() erc721_type = 721 @@ -363,7 +363,7 @@ def test_admin_can_mark_erc721_tokens_as_eligible_for_slots(self): def test_nonadmin_cannot_mark_erc721_tokens_as_eligible_for_slots(self): unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() erc721_type = 721 @@ -389,7 +389,7 @@ def test_admin_cannot_mark_erc721_tokens_as_eligible_for_slots_if_pool_id_is_non self, ): unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() erc721_type = 721 @@ -415,7 +415,7 @@ def test_admin_cannot_mark_erc721_tokens_as_eligible_for_slots_with_max_amount_g self, ): unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() erc721_type = 721 @@ -441,7 +441,7 @@ def test_admin_can_mark_erc721_tokens_as_eligible_for_slots_with_max_amount_1_th self, ): unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() erc721_type = 721 @@ -511,7 +511,7 @@ def test_admin_can_mark_erc721_tokens_as_eligible_for_slots_with_max_amount_1_th def test_admin_can_mark_erc1155_tokens_as_eligible_for_slots(self): # Testing with non-unequippable slot. unequippable = False - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() erc1155_type = 1155 @@ -565,7 +565,7 @@ def test_admin_can_mark_erc1155_tokens_as_eligible_for_slots(self): def test_nonadmin_cannot_mark_erc1155_tokens_as_eligible_for_slots(self): unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() erc1155_type = 1155 @@ -602,7 +602,7 @@ def test_player_can_equip_erc20_items_onto_their_subject_tokens(self): # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() # Set ERC20 token as equippable in slot with max amount of 10 @@ -629,7 +629,7 @@ def test_player_can_equip_erc20_items_onto_their_subject_tokens(self): self.assertEqual(player_balance_1, player_balance_0 - 2) self.assertEqual(inventory_balance_1, inventory_balance_0 + 2) - equipped_item = self.inventory.equipped(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item, (20, self.payment_token.address, 0, 2)) item_equipped_events = _fetch_events_chunk( @@ -676,7 +676,7 @@ def test_player_cannot_equip_too_many_erc20_items_onto_their_subject_tokens(self # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() # Set ERC20 token as equippable in slot with max amount of 10 @@ -704,7 +704,7 @@ def test_player_cannot_equip_too_many_erc20_items_onto_their_subject_tokens(self self.assertEqual(player_balance_1, player_balance_0) self.assertEqual(inventory_balance_1, inventory_balance_0) - equipped_item = self.inventory.equipped(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item, (0, ZERO_ADDRESS, 0, 0)) def test_player_can_equip_erc721_items_onto_their_subject_tokens(self): @@ -720,7 +720,7 @@ def test_player_can_equip_erc721_items_onto_their_subject_tokens(self): # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() # Set ERC721 token as equippable in slot with max amount of 1 @@ -742,7 +742,7 @@ def test_player_can_equip_erc721_items_onto_their_subject_tokens(self): self.assertEqual(self.item_nft.owner_of(item_token_id), self.inventory.address) - equipped_item = self.inventory.equipped(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item, (721, self.item_nft.address, item_token_id, 1)) item_equipped_events = _fetch_events_chunk( @@ -795,7 +795,7 @@ def test_player_cannot_equip_erc721_items_they_own_onto_subject_tokens_they_do_n # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() # Set ERC721 token as equippable in slot with max amount of 1 @@ -818,7 +818,7 @@ def test_player_cannot_equip_erc721_items_they_own_onto_subject_tokens_they_do_n self.assertEqual(self.item_nft.owner_of(item_token_id), self.player.address) - equipped_item = self.inventory.equipped(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item, (0, ZERO_ADDRESS, 0, 0)) def test_player_cannot_equip_erc721_items_which_they_do_not_own(self): @@ -836,7 +836,7 @@ def test_player_cannot_equip_erc721_items_which_they_do_not_own(self): # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() # Set ERC721 token as equippable in slot with max amount of 1 @@ -863,7 +863,7 @@ def test_player_cannot_equip_erc721_items_which_they_do_not_own(self): self.item_nft.owner_of(item_token_id), self.random_person.address ) - equipped_item = self.inventory.equipped(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item, (0, ZERO_ADDRESS, 0, 0)) def test_player_can_equip_erc1155_items_onto_their_subject_tokens(self): @@ -882,7 +882,7 @@ def test_player_can_equip_erc1155_items_onto_their_subject_tokens(self): # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() # Set ERC1155 token as equippable in slot with max amount of 10 @@ -913,7 +913,7 @@ def test_player_can_equip_erc1155_items_onto_their_subject_tokens(self): self.assertEqual(player_balance_1, player_balance_0 - 10) self.assertEqual(inventory_balance_1, inventory_balance_0 + 10) - equipped_item = self.inventory.equipped(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item, (1155, self.terminus.address, item_pool_id, 10)) item_equipped_events = _fetch_events_chunk( @@ -965,7 +965,7 @@ def test_player_cannot_equip_too_many_erc1155_items_onto_their_subject_tokens(se # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() # Set ERC1155 token as equippable in slot with max amount of 10 @@ -997,7 +997,7 @@ def test_player_cannot_equip_too_many_erc1155_items_onto_their_subject_tokens(se self.assertEqual(player_balance_1, player_balance_0) self.assertEqual(inventory_balance_1, inventory_balance_0) - equipped_item = self.inventory.equipped(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item, (0, ZERO_ADDRESS, 0, 0)) def test_player_can_unequip_all_erc20_items_in_slot_on_their_subject_tokens(self): @@ -1011,7 +1011,7 @@ def test_player_can_unequip_all_erc20_items_in_slot_on_their_subject_tokens(self # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() self.assertTrue(self.inventory.slot_is_unequippable(slot)) @@ -1023,7 +1023,7 @@ def test_player_can_unequip_all_erc20_items_in_slot_on_their_subject_tokens(self player_balance_0 = self.payment_token.balance_of(self.player.address) inventory_balance_0 = self.payment_token.balance_of(self.inventory.address) - equipped_item_0 = self.inventory.equipped(subject_token_id, slot) + equipped_item_0 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_0, (0, ZERO_ADDRESS, 0, 0)) self.inventory.equip( @@ -1042,7 +1042,7 @@ def test_player_can_unequip_all_erc20_items_in_slot_on_their_subject_tokens(self self.assertEqual(player_balance_1, player_balance_0 - 2) self.assertEqual(inventory_balance_1, inventory_balance_0 + 2) - equipped_item_1 = self.inventory.equipped(subject_token_id, slot) + equipped_item_1 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_1, (20, self.payment_token.address, 0, 2)) tx_receipt = self.inventory.unequip( @@ -1055,7 +1055,7 @@ def test_player_can_unequip_all_erc20_items_in_slot_on_their_subject_tokens(self self.assertEqual(player_balance_2, player_balance_0) self.assertEqual(inventory_balance_2, inventory_balance_0) - equipped_item_2 = self.inventory.equipped(subject_token_id, slot) + equipped_item_2 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_2, (0, ZERO_ADDRESS, 0, 0)) item_unequipped_events = _fetch_events_chunk( @@ -1104,7 +1104,7 @@ def test_player_can_unequip_some_but_not_all_erc20_items_in_slot_on_their_subjec # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() self.assertTrue(self.inventory.slot_is_unequippable(slot)) @@ -1116,7 +1116,7 @@ def test_player_can_unequip_some_but_not_all_erc20_items_in_slot_on_their_subjec player_balance_0 = self.payment_token.balance_of(self.player.address) inventory_balance_0 = self.payment_token.balance_of(self.inventory.address) - equipped_item_0 = self.inventory.equipped(subject_token_id, slot) + equipped_item_0 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_0, (0, ZERO_ADDRESS, 0, 0)) self.inventory.equip( @@ -1135,7 +1135,7 @@ def test_player_can_unequip_some_but_not_all_erc20_items_in_slot_on_their_subjec self.assertEqual(player_balance_1, player_balance_0 - 2) self.assertEqual(inventory_balance_1, inventory_balance_0 + 2) - equipped_item_1 = self.inventory.equipped(subject_token_id, slot) + equipped_item_1 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_1, (20, self.payment_token.address, 0, 2)) tx_receipt = self.inventory.unequip( @@ -1148,7 +1148,7 @@ def test_player_can_unequip_some_but_not_all_erc20_items_in_slot_on_their_subjec self.assertEqual(player_balance_2, player_balance_1 + 1) self.assertEqual(inventory_balance_2, inventory_balance_1 - 1) - equipped_item_2 = self.inventory.equipped(subject_token_id, slot) + equipped_item_2 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_2, (20, self.payment_token.address, 0, 1)) item_unequipped_events = _fetch_events_chunk( @@ -1197,7 +1197,7 @@ def test_player_can_unequip_all_erc721_items_in_slot_on_their_subject_tokens(sel # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() self.assertTrue(self.inventory.slot_is_unequippable(slot)) @@ -1214,7 +1214,7 @@ def test_player_can_unequip_all_erc721_items_in_slot_on_their_subject_tokens(sel self.assertEqual(self.item_nft.owner_of(item_token_id), self.player.address) - equipped_item_0 = self.inventory.equipped(subject_token_id, slot) + equipped_item_0 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_0, (0, ZERO_ADDRESS, 0, 0)) self.inventory.equip( @@ -1229,7 +1229,7 @@ def test_player_can_unequip_all_erc721_items_in_slot_on_their_subject_tokens(sel self.assertEqual(self.item_nft.owner_of(item_token_id), self.inventory.address) - equipped_item_1 = self.inventory.equipped(subject_token_id, slot) + equipped_item_1 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual( equipped_item_1, (721, self.item_nft.address, item_token_id, 1) ) @@ -1240,7 +1240,7 @@ def test_player_can_unequip_all_erc721_items_in_slot_on_their_subject_tokens(sel self.assertEqual(self.item_nft.owner_of(item_token_id), self.player.address) - equipped_item_2 = self.inventory.equipped(subject_token_id, slot) + equipped_item_2 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_2, (0, ZERO_ADDRESS, 0, 0)) item_unequipped_events = _fetch_events_chunk( @@ -1291,7 +1291,7 @@ def test_player_can_unequip_single_erc721_item_in_slot_on_their_subject_tokens_b # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() self.assertTrue(self.inventory.slot_is_unequippable(slot)) @@ -1308,7 +1308,7 @@ def test_player_can_unequip_single_erc721_item_in_slot_on_their_subject_tokens_b self.assertEqual(self.item_nft.owner_of(item_token_id), self.player.address) - equipped_item_0 = self.inventory.equipped(subject_token_id, slot) + equipped_item_0 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_0, (0, ZERO_ADDRESS, 0, 0)) self.inventory.equip( @@ -1323,7 +1323,7 @@ def test_player_can_unequip_single_erc721_item_in_slot_on_their_subject_tokens_b self.assertEqual(self.item_nft.owner_of(item_token_id), self.inventory.address) - equipped_item_1 = self.inventory.equipped(subject_token_id, slot) + equipped_item_1 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual( equipped_item_1, (721, self.item_nft.address, item_token_id, 1) ) @@ -1334,7 +1334,7 @@ def test_player_can_unequip_single_erc721_item_in_slot_on_their_subject_tokens_b self.assertEqual(self.item_nft.owner_of(item_token_id), self.player.address) - equipped_item_2 = self.inventory.equipped(subject_token_id, slot) + equipped_item_2 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_2, (0, ZERO_ADDRESS, 0, 0)) item_unequipped_events = _fetch_events_chunk( @@ -1386,7 +1386,7 @@ def test_player_can_unequip_all_erc1155_items_in_slot_on_their_subject_tokens(se # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() # Set ERC1155 token as equippable in slot with max amount of 10 @@ -1399,7 +1399,7 @@ def test_player_can_unequip_all_erc1155_items_in_slot_on_their_subject_tokens(se self.inventory.address, item_pool_id ) - equipped_item_0 = self.inventory.equipped(subject_token_id, slot) + equipped_item_0 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_0, (0, ZERO_ADDRESS, 0, 0)) self.inventory.equip( @@ -1420,7 +1420,7 @@ def test_player_can_unequip_all_erc1155_items_in_slot_on_their_subject_tokens(se self.assertEqual(player_balance_1, player_balance_0 - 9) self.assertEqual(inventory_balance_1, inventory_balance_0 + 9) - equipped_item_1 = self.inventory.equipped(subject_token_id, slot) + equipped_item_1 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual( equipped_item_1, (1155, self.terminus.address, item_pool_id, 9) ) @@ -1437,7 +1437,7 @@ def test_player_can_unequip_all_erc1155_items_in_slot_on_their_subject_tokens(se self.assertEqual(player_balance_2, player_balance_0) self.assertEqual(inventory_balance_2, inventory_balance_0) - equipped_item_2 = self.inventory.equipped(subject_token_id, slot) + equipped_item_2 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_2, (0, ZERO_ADDRESS, 0, 0)) item_unequipped_events = _fetch_events_chunk( @@ -1491,7 +1491,7 @@ def test_player_can_unequip_some_but_not_all_erc1155_items_in_slot_on_their_subj # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() # Set ERC1155 token as equippable in slot with max amount of 10 @@ -1504,7 +1504,7 @@ def test_player_can_unequip_some_but_not_all_erc1155_items_in_slot_on_their_subj self.inventory.address, item_pool_id ) - equipped_item_0 = self.inventory.equipped(subject_token_id, slot) + equipped_item_0 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item_0, (0, ZERO_ADDRESS, 0, 0)) self.inventory.equip( @@ -1525,7 +1525,7 @@ def test_player_can_unequip_some_but_not_all_erc1155_items_in_slot_on_their_subj self.assertEqual(player_balance_1, player_balance_0 - 9) self.assertEqual(inventory_balance_1, inventory_balance_0 + 9) - equipped_item_1 = self.inventory.equipped(subject_token_id, slot) + equipped_item_1 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual( equipped_item_1, (1155, self.terminus.address, item_pool_id, 9) ) @@ -1542,7 +1542,7 @@ def test_player_can_unequip_some_but_not_all_erc1155_items_in_slot_on_their_subj self.assertEqual(player_balance_2, player_balance_1 + 5) self.assertEqual(inventory_balance_2, inventory_balance_1 - 5) - equipped_item_2 = self.inventory.equipped(subject_token_id, slot) + equipped_item_2 = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual( equipped_item_2, (1155, self.terminus.address, item_pool_id, 4) ) @@ -1603,7 +1603,7 @@ def test_player_can_equip_an_item_and_then_replace_it_onto_their_subject_tokens_ # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, {"from": self.admin}) + self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) slot = self.inventory.num_slots() # Set ERC20 token as equippable in slot with max amount of 10 @@ -1639,7 +1639,7 @@ def test_player_can_equip_an_item_and_then_replace_it_onto_their_subject_tokens_ self.assertEqual(player_erc20_balance_1, player_erc20_balance_0 - 2) self.assertEqual(inventory_erc20_balance_1, inventory_erc20_balance_0 + 2) - equipped_item = self.inventory.equipped(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item, (20, self.payment_token.address, 0, 2)) player_erc1155_balance_1 = self.terminus.balance_of( @@ -1667,7 +1667,7 @@ def test_player_can_equip_an_item_and_then_replace_it_onto_their_subject_tokens_ self.assertEqual(player_erc20_balance_2, player_erc20_balance_0) self.assertEqual(inventory_erc20_balance_2, inventory_erc20_balance_0) - equipped_item = self.inventory.equipped(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) self.assertEqual(equipped_item, (1155, self.terminus.address, item_pool_id, 9)) player_erc1155_balance_2 = self.terminus.balance_of( From ca9ed0e8930e69960d41f2c233c485987b4f7769 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Sat, 28 Jan 2023 17:03:58 -0300 Subject: [PATCH 06/14] fix(inventory): Format code with black *.* --- game7ctl/game7ctl/test_inventory.py | 196 ++++++++++++++++++++++++---- 1 file changed, 168 insertions(+), 28 deletions(-) diff --git a/game7ctl/game7ctl/test_inventory.py b/game7ctl/game7ctl/test_inventory.py index ee33f3a..7837074 100644 --- a/game7ctl/game7ctl/test_inventory.py +++ b/game7ctl/game7ctl/test_inventory.py @@ -113,7 +113,12 @@ def test_admin_can_create_nonunequippable_slot(self): unequippable = False num_slots_0 = self.inventory.num_slots() - tx_receipt = self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + tx_receipt = self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) num_slots_1 = self.inventory.num_slots() self.assertEqual(num_slots_1, num_slots_0 + 1) @@ -144,7 +149,12 @@ def test_admin_can_create_unequippable_slot(self): unequippable = True num_slots_0 = self.inventory.num_slots() - tx_receipt = self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + tx_receipt = self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) num_slots_1 = self.inventory.num_slots() self.assertEqual(num_slots_1, num_slots_0 + 1) @@ -176,7 +186,12 @@ def test_nonadmin_cannot_create_slot(self): num_slots_0 = self.inventory.num_slots() with self.assertRaises(VirtualMachineError): - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.player}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.player}, + ) num_slots_1 = self.inventory.num_slots() self.assertEqual(num_slots_1, num_slots_0) @@ -185,7 +200,12 @@ def test_admin_cannot_mark_contracts_with_invalid_type_as_eligible_for_slots( self, ): unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() invalid_type = 0 @@ -209,7 +229,12 @@ def test_admin_cannot_mark_contracts_with_invalid_type_as_eligible_for_slots( def test_admin_can_mark_erc20_tokens_as_eligible_for_slots(self): unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() erc20_type = 20 @@ -261,7 +286,12 @@ def test_admin_can_mark_erc20_tokens_as_eligible_for_slots(self): def test_nonadmin_cannot_mark_erc20_tokens_as_eligible_for_slots(self): unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() erc20_type = 20 @@ -287,7 +317,12 @@ def test_admin_cannot_mark_erc20_tokens_as_eligible_for_slots_if_pool_id_is_nonz self, ): unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() erc20_type = 20 @@ -311,7 +346,12 @@ def test_admin_cannot_mark_erc20_tokens_as_eligible_for_slots_if_pool_id_is_nonz def test_admin_can_mark_erc721_tokens_as_eligible_for_slots(self): unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() erc721_type = 721 @@ -363,7 +403,12 @@ def test_admin_can_mark_erc721_tokens_as_eligible_for_slots(self): def test_nonadmin_cannot_mark_erc721_tokens_as_eligible_for_slots(self): unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() erc721_type = 721 @@ -389,7 +434,12 @@ def test_admin_cannot_mark_erc721_tokens_as_eligible_for_slots_if_pool_id_is_non self, ): unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() erc721_type = 721 @@ -415,7 +465,12 @@ def test_admin_cannot_mark_erc721_tokens_as_eligible_for_slots_with_max_amount_g self, ): unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() erc721_type = 721 @@ -441,7 +496,12 @@ def test_admin_can_mark_erc721_tokens_as_eligible_for_slots_with_max_amount_1_th self, ): unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() erc721_type = 721 @@ -511,7 +571,12 @@ def test_admin_can_mark_erc721_tokens_as_eligible_for_slots_with_max_amount_1_th def test_admin_can_mark_erc1155_tokens_as_eligible_for_slots(self): # Testing with non-unequippable slot. unequippable = False - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() erc1155_type = 1155 @@ -565,7 +630,12 @@ def test_admin_can_mark_erc1155_tokens_as_eligible_for_slots(self): def test_nonadmin_cannot_mark_erc1155_tokens_as_eligible_for_slots(self): unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() erc1155_type = 1155 @@ -602,7 +672,12 @@ def test_player_can_equip_erc20_items_onto_their_subject_tokens(self): # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() # Set ERC20 token as equippable in slot with max amount of 10 @@ -676,7 +751,12 @@ def test_player_cannot_equip_too_many_erc20_items_onto_their_subject_tokens(self # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() # Set ERC20 token as equippable in slot with max amount of 10 @@ -720,7 +800,12 @@ def test_player_can_equip_erc721_items_onto_their_subject_tokens(self): # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() # Set ERC721 token as equippable in slot with max amount of 1 @@ -795,7 +880,12 @@ def test_player_cannot_equip_erc721_items_they_own_onto_subject_tokens_they_do_n # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() # Set ERC721 token as equippable in slot with max amount of 1 @@ -836,7 +926,12 @@ def test_player_cannot_equip_erc721_items_which_they_do_not_own(self): # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() # Set ERC721 token as equippable in slot with max amount of 1 @@ -882,7 +977,12 @@ def test_player_can_equip_erc1155_items_onto_their_subject_tokens(self): # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() # Set ERC1155 token as equippable in slot with max amount of 10 @@ -965,7 +1065,12 @@ def test_player_cannot_equip_too_many_erc1155_items_onto_their_subject_tokens(se # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() # Set ERC1155 token as equippable in slot with max amount of 10 @@ -1011,7 +1116,12 @@ def test_player_can_unequip_all_erc20_items_in_slot_on_their_subject_tokens(self # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() self.assertTrue(self.inventory.slot_is_unequippable(slot)) @@ -1104,7 +1214,12 @@ def test_player_can_unequip_some_but_not_all_erc20_items_in_slot_on_their_subjec # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() self.assertTrue(self.inventory.slot_is_unequippable(slot)) @@ -1197,7 +1312,12 @@ def test_player_can_unequip_all_erc721_items_in_slot_on_their_subject_tokens(sel # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() self.assertTrue(self.inventory.slot_is_unequippable(slot)) @@ -1291,7 +1411,12 @@ def test_player_can_unequip_single_erc721_item_in_slot_on_their_subject_tokens_b # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() self.assertTrue(self.inventory.slot_is_unequippable(slot)) @@ -1386,7 +1511,12 @@ def test_player_can_unequip_all_erc1155_items_in_slot_on_their_subject_tokens(se # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() # Set ERC1155 token as equippable in slot with max amount of 10 @@ -1491,7 +1621,12 @@ def test_player_can_unequip_some_but_not_all_erc1155_items_in_slot_on_their_subj # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() # Set ERC1155 token as equippable in slot with max amount of 10 @@ -1603,7 +1738,12 @@ def test_player_can_equip_an_item_and_then_replace_it_onto_their_subject_tokens_ # Create inventory slot unequippable = True - self.inventory.create_slot(unequippable, slot_type=1, slot_uri="random_uri", transaction_config={"from": self.admin}) + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) slot = self.inventory.num_slots() # Set ERC20 token as equippable in slot with max amount of 10 From 473e8d58cbfb399984b8817b85560b5ec7a40455 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Mon, 30 Jan 2023 10:20:11 -0300 Subject: [PATCH 07/14] wip(inventory): rename inventory-gogogo cli to "contracts" --- README.md | 8 +++---- game7ctl/game7ctl/core.py | 34 ++++++++++++++--------------- game7ctl/game7ctl/test_inventory.py | 4 ++-- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index faf81a3..38e69f3 100644 --- a/README.md +++ b/README.md @@ -66,13 +66,13 @@ If you want to register your contract for automatic regeneration, please add it ### `game7ctl` Once you have set up `game7ctl`, you can use it to deploy the contracts in this repository. For example, -to deploy the Inventory contract as a Diamond proxy, you would use the `game7ctl core inventory-gogogo` command. +to deploy the Inventory contract as a Diamond proxy, you would use the `game7ctl core contracts` command. To see all the parameters you can pass in the deployment, run: ``` -$ game7ctl core inventory-gogogo --help -usage: game7ctl inventory-gogogo [-h] --network NETWORK [--address ADDRESS] --sender SENDER [--password PASSWORD] [--gas-price GAS_PRICE] [--max-fee-per-gas MAX_FEE_PER_GAS] +$ game7ctl core contracts --help +usage: game7ctl contracts [-h] --network NETWORK [--address ADDRESS] --sender SENDER [--password PASSWORD] [--gas-price GAS_PRICE] [--max-fee-per-gas MAX_FEE_PER_GAS] [--max-priority-fee-per-gas MAX_PRIORITY_FEE_PER_GAS] [--confirmations CONFIRMATIONS] [--nonce NONCE] [--value VALUE] [--verbose] --admin-terminus-address ADMIN_TERMINUS_ADDRESS --admin-terminus-pool-id ADMIN_TERMINUS_POOL_ID --subject-erc721-address SUBJECT_ERC721_ADDRESS [--diamond-cut-address DIAMOND_CUT_ADDRESS] [--diamond-address DIAMOND_ADDRESS] [--diamond-loupe-address DIAMOND_LOUPE_ADDRESS] @@ -158,6 +158,6 @@ If you follow all the explanations above, you should be able to deploy the Inven Using a command like this: ``` -game7ctl core inventory-gogogo --network --admin-terminus-address --admin-terminus-pool-id --sender --subject-erc721-address +game7ctl core contracts --network --admin-terminus-address --admin-terminus-pool-id --sender --subject-erc721-address ``` diff --git a/game7ctl/game7ctl/core.py b/game7ctl/game7ctl/core.py index 1778ce7..8ae44af 100644 --- a/game7ctl/game7ctl/core.py +++ b/game7ctl/game7ctl/core.py @@ -280,7 +280,7 @@ def diamond_gogogo( return result -def inventory_gogogo( +def contracts( admin_terminus_address: str, admin_terminus_pool_id: int, subject_erc721_address: str, @@ -353,10 +353,10 @@ def handle_facet_cut(args: argparse.Namespace) -> None: ) -def handle_inventory_gogogo(args: argparse.Namespace) -> None: +def handle_contracts(args: argparse.Namespace) -> None: network.connect(args.network) transaction_config = InventoryFacet.get_transaction_config(args) - result = inventory_gogogo( + result = contracts( admin_terminus_address=args.admin_terminus_address, admin_terminus_pool_id=args.admin_terminus_pool_id, subject_erc721_address=args.subject_erc721_address, @@ -431,64 +431,64 @@ def generate_cli(): ) facet_cut_parser.set_defaults(func=handle_facet_cut) - inventory_gogogo_parser = subcommands.add_parser( - "inventory-gogogo", - description="Deploy Inventory diamond contract", + contracts_parser = subcommands.add_parser( + "contracts", + description="Deploy G7 diamond contract", ) - Diamond.add_default_arguments(inventory_gogogo_parser, transact=True) - inventory_gogogo_parser.add_argument( + Diamond.add_default_arguments(contracts_parser, transact=True) + contracts_parser.add_argument( "--admin-terminus-address", required=True, help="Address of Terminus contract defining access control for this GardenOfForkingPaths contract", ) - inventory_gogogo_parser.add_argument( + contracts_parser.add_argument( "--admin-terminus-pool-id", required=True, type=int, help="Pool ID of Terminus pool for administrators of this GardenOfForkingPaths contract", ) - inventory_gogogo_parser.add_argument( + contracts_parser.add_argument( "--subject-erc721-address", required=True, help="Address of ERC721 contract that the Inventory modifies", ) - inventory_gogogo_parser.add_argument( + contracts_parser.add_argument( "--diamond-cut-address", required=False, default=None, help="Address to deployed DiamondCutFacet. If provided, this command skips deployment of a new DiamondCutFacet.", ) - inventory_gogogo_parser.add_argument( + contracts_parser.add_argument( "--diamond-address", required=False, default=None, help="Address to deployed Diamond contract. If provided, this command skips deployment of a new Diamond contract and simply mounts the required facets onto the existing Diamond contract. Assumes that there is no collision of selectors.", ) - inventory_gogogo_parser.add_argument( + contracts_parser.add_argument( "--diamond-loupe-address", required=False, default=None, help="Address to deployed DiamondLoupeFacet. If provided, this command skips deployment of a new DiamondLoupeFacet. It mounts the existing DiamondLoupeFacet onto the Diamond.", ) - inventory_gogogo_parser.add_argument( + contracts_parser.add_argument( "--ownership-address", required=False, default=None, help="Address to deployed OwnershipFacet. If provided, this command skips deployment of a new OwnershipFacet. It mounts the existing OwnershipFacet onto the Diamond.", ) - inventory_gogogo_parser.add_argument( + contracts_parser.add_argument( "--inventory-facet-address", required=False, default=None, help="Address to deployed InventoryFacet. If provided, this command skips deployment of a new InventoryFacet. It mounts the existing InventoryFacet onto the Diamond.", ) - inventory_gogogo_parser.add_argument( + contracts_parser.add_argument( "-o", "--outfile", type=argparse.FileType("w"), default=None, help="(Optional) file to write deployed addresses to", ) - inventory_gogogo_parser.set_defaults(func=handle_inventory_gogogo) + contracts_parser.set_defaults(func=handle_contracts) return parser diff --git a/game7ctl/game7ctl/test_inventory.py b/game7ctl/game7ctl/test_inventory.py index 7837074..7dfb2da 100644 --- a/game7ctl/game7ctl/test_inventory.py +++ b/game7ctl/game7ctl/test_inventory.py @@ -6,7 +6,7 @@ from moonworm.watch import _fetch_events_chunk from . import InventoryFacet, MockERC20, MockERC721, MockTerminus, inventory_events -from .core import inventory_gogogo +from .core import contracts MAX_UINT = 2**256 - 1 @@ -54,7 +54,7 @@ def setUpClass(cls) -> None: ) cls.predeployment_block = len(chain) - cls.deployed_contracts = inventory_gogogo( + cls.deployed_contracts = contracts( cls.terminus.address, cls.admin_terminus_pool_id, cls.nft.address, From f3617a4477b214a2f078757d42e9e31d21219be1 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Mon, 30 Jan 2023 10:22:43 -0300 Subject: [PATCH 08/14] wip(inventory): rename inventory-gogogo cli to "contracts" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38e69f3..dfaa78f 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ brownie networks add Polygon $NETWORK_NAME host=$JSONRPC_URL chainid=137 explore The only keys which are not optional are `chainid` and `host`. -Then, you could pass `--network $NETWORK_NAME` as an argument to `game7ctl core inventory-facet-deploy`. +Then, you could pass `--network $NETWORK_NAME` as an argument to `game7ctl core contracts`. ##### `--sender` From c3168d121cdd58dab5198499654c1ce4b2357671 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Mon, 30 Jan 2023 10:35:28 -0300 Subject: [PATCH 09/14] fix(inventory): add default slot type as "unknown" --- contracts/facets/InventoryFacet.sol | 10 +++++++++- contracts/libraries/LibInventory.sol | 14 ++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/contracts/facets/InventoryFacet.sol b/contracts/facets/InventoryFacet.sol index f968758..26f5ff7 100644 --- a/contracts/facets/InventoryFacet.sol +++ b/contracts/facets/InventoryFacet.sol @@ -86,6 +86,14 @@ contract InventoryFacet is _; } + modifier requireValidSlotType(uint256 slotType) { + require( + slotType <= uint(LibInventory.SlotType.Trophies) && slotType >= uint(LibInventory.SlotType.Unknown), + "InventoryFacet.createSlot: Invalid slot type" + ); + _; + } + /** An Inventory must be initialized with: 1. adminTerminusAddress: The address for the Terminus contract which hosts the Administrator badge. @@ -125,9 +133,9 @@ contract InventoryFacet is ) external onlyAdmin + requireValidSlotType(slotType) returns (uint256) { - require(slotType <= uint(LibInventory.SlotType.Trophies) && slotType >= uint(LibInventory.SlotType.Clothes)); LibInventory.InventoryStorage storage istore = LibInventory .inventoryStorage(); diff --git a/contracts/libraries/LibInventory.sol b/contracts/libraries/LibInventory.sol index 9d3d3f5..ab04b5b 100644 --- a/contracts/libraries/LibInventory.sol +++ b/contracts/libraries/LibInventory.sol @@ -14,12 +14,14 @@ library LibInventory { uint256 constant ERC1155_ITEM_TYPE = 1155; // Returns uint - // Clothes - 0 - // Accesories - 1 - // Materials - 2 - // Badges - 3 - // Trophies - 4 - enum SlotType { + // Unknown - 0 + // Clothes - 1 + // Accesories - 2 + // Materials - 3 + // Badges - 4 + // Trophies - 5 + enum SlotType { + Unknown, Clothes, Accesories, Materials, From 59f7832446c61901810feb4e2d0a8df51ad2fe35 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Mon, 30 Jan 2023 10:57:23 -0300 Subject: [PATCH 10/14] fix(inventory): adding the correct slot URI setter modifier, only admins --- contracts/facets/InventoryFacet.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/facets/InventoryFacet.sol b/contracts/facets/InventoryFacet.sol index 26f5ff7..2016dda 100644 --- a/contracts/facets/InventoryFacet.sol +++ b/contracts/facets/InventoryFacet.sol @@ -200,8 +200,7 @@ contract InventoryFacet is return istore.SlotData[slotId].SlotURI; } - // @TODO: @ogarciarevett add slotOwner modifier - function setSlotUri(string memory newSlotURI, uint slotId) external diamondNonReentrant { + function setSlotUri(string memory newSlotURI, uint slotId) external onlyAdmin { LibInventory.InventoryStorage storage istore = LibInventory .inventoryStorage(); From ec08a887cbd7d387b60a43f299a9072a57479bd7 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Mon, 30 Jan 2023 11:20:28 -0300 Subject: [PATCH 11/14] fix(inventory): rename getEquippedItems to getEquippedItem --- contracts/facets/InventoryFacet.sol | 2 +- contracts/interfaces/IInventory.sol | 2 +- game7ctl/game7ctl/InventoryFacet.py | 18 +++++----- game7ctl/game7ctl/test_inventory.py | 54 ++++++++++++++--------------- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/contracts/facets/InventoryFacet.sol b/contracts/facets/InventoryFacet.sol index 2016dda..d1d3ba3 100644 --- a/contracts/facets/InventoryFacet.sol +++ b/contracts/facets/InventoryFacet.sol @@ -476,7 +476,7 @@ contract InventoryFacet is _unequip(subjectTokenId, slot, unequipAll, amount); } - function getEquippedItems(uint256 subjectTokenId, uint256 slot) + function getEquippedItem(uint256 subjectTokenId, uint256 slot) external view returns (LibInventory.EquippedItem memory item) diff --git a/contracts/interfaces/IInventory.sol b/contracts/interfaces/IInventory.sol index b64def1..468eddb 100644 --- a/contracts/interfaces/IInventory.sol +++ b/contracts/interfaces/IInventory.sol @@ -95,7 +95,7 @@ interface IInventory { uint256 amount ) external; - function getEquippedItems(uint256 subjectTokenId, uint256 slot) + function getEquippedItem(uint256 subjectTokenId, uint256 slot) external view returns (LibInventory.EquippedItem memory item); diff --git a/game7ctl/game7ctl/InventoryFacet.py b/game7ctl/game7ctl/InventoryFacet.py index f69b93d..53c3f6e 100644 --- a/game7ctl/game7ctl/InventoryFacet.py +++ b/game7ctl/game7ctl/InventoryFacet.py @@ -139,14 +139,14 @@ def equip( transaction_config, ) - def get_equipped_items( + def get_equipped_item( self, subject_token_id: int, slot: int, block_number: Optional[Union[str, int]] = "latest", ) -> Any: self.assert_contract_is_instantiated() - return self.contract.getEquippedItems.call( + return self.contract.getEquippedItem.call( subject_token_id, slot, block_identifier=block_number ) @@ -438,10 +438,10 @@ def handle_equip(args: argparse.Namespace) -> None: print(result.info()) -def handle_get_equipped_items(args: argparse.Namespace) -> None: +def handle_get_equipped_item(args: argparse.Namespace) -> None: network.connect(args.network) contract = InventoryFacet(args.address) - result = contract.get_equipped_items( + result = contract.get_equipped_item( subject_token_id=args.subject_token_id, slot=args.slot, block_number=args.block_number, @@ -693,15 +693,15 @@ def generate_cli() -> argparse.ArgumentParser: equip_parser.add_argument("--amount", required=True, help="Type: uint256", type=int) equip_parser.set_defaults(func=handle_equip) - get_equipped_items_parser = subcommands.add_parser("get-equipped-items") - add_default_arguments(get_equipped_items_parser, False) - get_equipped_items_parser.add_argument( + get_equipped_item_parser = subcommands.add_parser("get-equipped-item") + add_default_arguments(get_equipped_item_parser, False) + get_equipped_item_parser.add_argument( "--subject-token-id", required=True, help="Type: uint256", type=int ) - get_equipped_items_parser.add_argument( + get_equipped_item_parser.add_argument( "--slot", required=True, help="Type: uint256", type=int ) - get_equipped_items_parser.set_defaults(func=handle_get_equipped_items) + get_equipped_item_parser.set_defaults(func=handle_get_equipped_item) get_slot_by_id_parser = subcommands.add_parser("get-slot-by-id") add_default_arguments(get_slot_by_id_parser, False) diff --git a/game7ctl/game7ctl/test_inventory.py b/game7ctl/game7ctl/test_inventory.py index 7dfb2da..fa04f75 100644 --- a/game7ctl/game7ctl/test_inventory.py +++ b/game7ctl/game7ctl/test_inventory.py @@ -704,7 +704,7 @@ def test_player_can_equip_erc20_items_onto_their_subject_tokens(self): self.assertEqual(player_balance_1, player_balance_0 - 2) self.assertEqual(inventory_balance_1, inventory_balance_0 + 2) - equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item, (20, self.payment_token.address, 0, 2)) item_equipped_events = _fetch_events_chunk( @@ -784,7 +784,7 @@ def test_player_cannot_equip_too_many_erc20_items_onto_their_subject_tokens(self self.assertEqual(player_balance_1, player_balance_0) self.assertEqual(inventory_balance_1, inventory_balance_0) - equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item, (0, ZERO_ADDRESS, 0, 0)) def test_player_can_equip_erc721_items_onto_their_subject_tokens(self): @@ -827,7 +827,7 @@ def test_player_can_equip_erc721_items_onto_their_subject_tokens(self): self.assertEqual(self.item_nft.owner_of(item_token_id), self.inventory.address) - equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item, (721, self.item_nft.address, item_token_id, 1)) item_equipped_events = _fetch_events_chunk( @@ -908,7 +908,7 @@ def test_player_cannot_equip_erc721_items_they_own_onto_subject_tokens_they_do_n self.assertEqual(self.item_nft.owner_of(item_token_id), self.player.address) - equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item, (0, ZERO_ADDRESS, 0, 0)) def test_player_cannot_equip_erc721_items_which_they_do_not_own(self): @@ -958,7 +958,7 @@ def test_player_cannot_equip_erc721_items_which_they_do_not_own(self): self.item_nft.owner_of(item_token_id), self.random_person.address ) - equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item, (0, ZERO_ADDRESS, 0, 0)) def test_player_can_equip_erc1155_items_onto_their_subject_tokens(self): @@ -1013,7 +1013,7 @@ def test_player_can_equip_erc1155_items_onto_their_subject_tokens(self): self.assertEqual(player_balance_1, player_balance_0 - 10) self.assertEqual(inventory_balance_1, inventory_balance_0 + 10) - equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item, (1155, self.terminus.address, item_pool_id, 10)) item_equipped_events = _fetch_events_chunk( @@ -1102,7 +1102,7 @@ def test_player_cannot_equip_too_many_erc1155_items_onto_their_subject_tokens(se self.assertEqual(player_balance_1, player_balance_0) self.assertEqual(inventory_balance_1, inventory_balance_0) - equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item, (0, ZERO_ADDRESS, 0, 0)) def test_player_can_unequip_all_erc20_items_in_slot_on_their_subject_tokens(self): @@ -1133,7 +1133,7 @@ def test_player_can_unequip_all_erc20_items_in_slot_on_their_subject_tokens(self player_balance_0 = self.payment_token.balance_of(self.player.address) inventory_balance_0 = self.payment_token.balance_of(self.inventory.address) - equipped_item_0 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_0 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_0, (0, ZERO_ADDRESS, 0, 0)) self.inventory.equip( @@ -1152,7 +1152,7 @@ def test_player_can_unequip_all_erc20_items_in_slot_on_their_subject_tokens(self self.assertEqual(player_balance_1, player_balance_0 - 2) self.assertEqual(inventory_balance_1, inventory_balance_0 + 2) - equipped_item_1 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_1 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_1, (20, self.payment_token.address, 0, 2)) tx_receipt = self.inventory.unequip( @@ -1165,7 +1165,7 @@ def test_player_can_unequip_all_erc20_items_in_slot_on_their_subject_tokens(self self.assertEqual(player_balance_2, player_balance_0) self.assertEqual(inventory_balance_2, inventory_balance_0) - equipped_item_2 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_2 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_2, (0, ZERO_ADDRESS, 0, 0)) item_unequipped_events = _fetch_events_chunk( @@ -1231,7 +1231,7 @@ def test_player_can_unequip_some_but_not_all_erc20_items_in_slot_on_their_subjec player_balance_0 = self.payment_token.balance_of(self.player.address) inventory_balance_0 = self.payment_token.balance_of(self.inventory.address) - equipped_item_0 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_0 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_0, (0, ZERO_ADDRESS, 0, 0)) self.inventory.equip( @@ -1250,7 +1250,7 @@ def test_player_can_unequip_some_but_not_all_erc20_items_in_slot_on_their_subjec self.assertEqual(player_balance_1, player_balance_0 - 2) self.assertEqual(inventory_balance_1, inventory_balance_0 + 2) - equipped_item_1 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_1 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_1, (20, self.payment_token.address, 0, 2)) tx_receipt = self.inventory.unequip( @@ -1263,7 +1263,7 @@ def test_player_can_unequip_some_but_not_all_erc20_items_in_slot_on_their_subjec self.assertEqual(player_balance_2, player_balance_1 + 1) self.assertEqual(inventory_balance_2, inventory_balance_1 - 1) - equipped_item_2 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_2 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_2, (20, self.payment_token.address, 0, 1)) item_unequipped_events = _fetch_events_chunk( @@ -1334,7 +1334,7 @@ def test_player_can_unequip_all_erc721_items_in_slot_on_their_subject_tokens(sel self.assertEqual(self.item_nft.owner_of(item_token_id), self.player.address) - equipped_item_0 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_0 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_0, (0, ZERO_ADDRESS, 0, 0)) self.inventory.equip( @@ -1349,7 +1349,7 @@ def test_player_can_unequip_all_erc721_items_in_slot_on_their_subject_tokens(sel self.assertEqual(self.item_nft.owner_of(item_token_id), self.inventory.address) - equipped_item_1 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_1 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual( equipped_item_1, (721, self.item_nft.address, item_token_id, 1) ) @@ -1360,7 +1360,7 @@ def test_player_can_unequip_all_erc721_items_in_slot_on_their_subject_tokens(sel self.assertEqual(self.item_nft.owner_of(item_token_id), self.player.address) - equipped_item_2 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_2 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_2, (0, ZERO_ADDRESS, 0, 0)) item_unequipped_events = _fetch_events_chunk( @@ -1433,7 +1433,7 @@ def test_player_can_unequip_single_erc721_item_in_slot_on_their_subject_tokens_b self.assertEqual(self.item_nft.owner_of(item_token_id), self.player.address) - equipped_item_0 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_0 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_0, (0, ZERO_ADDRESS, 0, 0)) self.inventory.equip( @@ -1448,7 +1448,7 @@ def test_player_can_unequip_single_erc721_item_in_slot_on_their_subject_tokens_b self.assertEqual(self.item_nft.owner_of(item_token_id), self.inventory.address) - equipped_item_1 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_1 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual( equipped_item_1, (721, self.item_nft.address, item_token_id, 1) ) @@ -1459,7 +1459,7 @@ def test_player_can_unequip_single_erc721_item_in_slot_on_their_subject_tokens_b self.assertEqual(self.item_nft.owner_of(item_token_id), self.player.address) - equipped_item_2 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_2 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_2, (0, ZERO_ADDRESS, 0, 0)) item_unequipped_events = _fetch_events_chunk( @@ -1529,7 +1529,7 @@ def test_player_can_unequip_all_erc1155_items_in_slot_on_their_subject_tokens(se self.inventory.address, item_pool_id ) - equipped_item_0 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_0 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_0, (0, ZERO_ADDRESS, 0, 0)) self.inventory.equip( @@ -1550,7 +1550,7 @@ def test_player_can_unequip_all_erc1155_items_in_slot_on_their_subject_tokens(se self.assertEqual(player_balance_1, player_balance_0 - 9) self.assertEqual(inventory_balance_1, inventory_balance_0 + 9) - equipped_item_1 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_1 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual( equipped_item_1, (1155, self.terminus.address, item_pool_id, 9) ) @@ -1567,7 +1567,7 @@ def test_player_can_unequip_all_erc1155_items_in_slot_on_their_subject_tokens(se self.assertEqual(player_balance_2, player_balance_0) self.assertEqual(inventory_balance_2, inventory_balance_0) - equipped_item_2 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_2 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_2, (0, ZERO_ADDRESS, 0, 0)) item_unequipped_events = _fetch_events_chunk( @@ -1639,7 +1639,7 @@ def test_player_can_unequip_some_but_not_all_erc1155_items_in_slot_on_their_subj self.inventory.address, item_pool_id ) - equipped_item_0 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_0 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item_0, (0, ZERO_ADDRESS, 0, 0)) self.inventory.equip( @@ -1660,7 +1660,7 @@ def test_player_can_unequip_some_but_not_all_erc1155_items_in_slot_on_their_subj self.assertEqual(player_balance_1, player_balance_0 - 9) self.assertEqual(inventory_balance_1, inventory_balance_0 + 9) - equipped_item_1 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_1 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual( equipped_item_1, (1155, self.terminus.address, item_pool_id, 9) ) @@ -1677,7 +1677,7 @@ def test_player_can_unequip_some_but_not_all_erc1155_items_in_slot_on_their_subj self.assertEqual(player_balance_2, player_balance_1 + 5) self.assertEqual(inventory_balance_2, inventory_balance_1 - 5) - equipped_item_2 = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item_2 = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual( equipped_item_2, (1155, self.terminus.address, item_pool_id, 4) ) @@ -1779,7 +1779,7 @@ def test_player_can_equip_an_item_and_then_replace_it_onto_their_subject_tokens_ self.assertEqual(player_erc20_balance_1, player_erc20_balance_0 - 2) self.assertEqual(inventory_erc20_balance_1, inventory_erc20_balance_0 + 2) - equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item, (20, self.payment_token.address, 0, 2)) player_erc1155_balance_1 = self.terminus.balance_of( @@ -1807,7 +1807,7 @@ def test_player_can_equip_an_item_and_then_replace_it_onto_their_subject_tokens_ self.assertEqual(player_erc20_balance_2, player_erc20_balance_0) self.assertEqual(inventory_erc20_balance_2, inventory_erc20_balance_0) - equipped_item = self.inventory.get_equipped_items(subject_token_id, slot) + equipped_item = self.inventory.get_equipped_item(subject_token_id, slot) self.assertEqual(equipped_item, (1155, self.terminus.address, item_pool_id, 9)) player_erc1155_balance_2 = self.terminus.balance_of( From e90f51ea66544c9a7063f83587170edb5d898dc3 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Mon, 30 Jan 2023 17:38:30 -0300 Subject: [PATCH 12/14] fix(inventory): Change slot management, add mapping for sloTypes, now optional. Missing tests --- README.md | 10 ++--- contracts/facets/InventoryFacet.sol | 62 ++++++++++++++++------------ contracts/interfaces/IInventory.sol | 8 +++- contracts/libraries/LibInventory.sol | 31 +++++--------- game7ctl/game7ctl/cli.py | 3 ++ game7ctl/game7ctl/core.py | 13 +++--- game7ctl/game7ctl/test_inventory.py | 4 +- 7 files changed, 70 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index dfaa78f..59f9380 100644 --- a/README.md +++ b/README.md @@ -66,13 +66,13 @@ If you want to register your contract for automatic regeneration, please add it ### `game7ctl` Once you have set up `game7ctl`, you can use it to deploy the contracts in this repository. For example, -to deploy the Inventory contract as a Diamond proxy, you would use the `game7ctl core contracts` command. +to deploy the Inventory contract as a Diamond proxy, you would use the `game7ctl core dao` command. To see all the parameters you can pass in the deployment, run: ``` -$ game7ctl core contracts --help -usage: game7ctl contracts [-h] --network NETWORK [--address ADDRESS] --sender SENDER [--password PASSWORD] [--gas-price GAS_PRICE] [--max-fee-per-gas MAX_FEE_PER_GAS] +$ game7ctl core dao --help +usage: game7ctl dao [-h] --network NETWORK [--address ADDRESS] --sender SENDER [--password PASSWORD] [--gas-price GAS_PRICE] [--max-fee-per-gas MAX_FEE_PER_GAS] [--max-priority-fee-per-gas MAX_PRIORITY_FEE_PER_GAS] [--confirmations CONFIRMATIONS] [--nonce NONCE] [--value VALUE] [--verbose] --admin-terminus-address ADMIN_TERMINUS_ADDRESS --admin-terminus-pool-id ADMIN_TERMINUS_POOL_ID --subject-erc721-address SUBJECT_ERC721_ADDRESS [--diamond-cut-address DIAMOND_CUT_ADDRESS] [--diamond-address DIAMOND_ADDRESS] [--diamond-loupe-address DIAMOND_LOUPE_ADDRESS] @@ -132,7 +132,7 @@ brownie networks add Polygon $NETWORK_NAME host=$JSONRPC_URL chainid=137 explore The only keys which are not optional are `chainid` and `host`. -Then, you could pass `--network $NETWORK_NAME` as an argument to `game7ctl core contracts`. +Then, you could pass `--network $NETWORK_NAME` as an argument to `game7ctl core dao`. ##### `--sender` @@ -158,6 +158,6 @@ If you follow all the explanations above, you should be able to deploy the Inven Using a command like this: ``` -game7ctl core contracts --network --admin-terminus-address --admin-terminus-pool-id --sender --subject-erc721-address +game7ctl core dao --network --admin-terminus-address --admin-terminus-pool-id --sender --subject-erc721-address ``` diff --git a/contracts/facets/InventoryFacet.sol b/contracts/facets/InventoryFacet.sol index d1d3ba3..7a589a5 100644 --- a/contracts/facets/InventoryFacet.sol +++ b/contracts/facets/InventoryFacet.sol @@ -64,18 +64,6 @@ contract InventoryFacet is _; } - // TODO: @ogarciarevett finish this - // modifier onlySlotOwner(uint256 slotId) { - // // LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); - - // // // TODO: @ogarciarevett check if asking for the msg.sender will be required, if the user change the wallet could loose this relation - // // istore.SubjectSlots[msg.sender] - - // // require(msg.sender); - - // _; - // } - modifier requireValidItemType(uint256 itemType) { require( itemType == LibInventory.ERC20_ITEM_TYPE || @@ -86,10 +74,22 @@ contract InventoryFacet is _; } - modifier requireValidSlotType(uint256 slotType) { + modifier requireSubjectBlacklistedForSlot(uint256 toSubjectTokenId, uint256 slotId) { + LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); + require( - slotType <= uint(LibInventory.SlotType.Trophies) && slotType >= uint(LibInventory.SlotType.Unknown), - "InventoryFacet.createSlot: Invalid slot type" + istore.IsSubjectTokenBlackListedForSlot[istore.ContractERC721Address][toSubjectTokenId][slotId] == true, + "InventoryFacet.requireSubjectWhitelistedForSlot: The subject is not in the whitelist for this slot" + ); + _; + } + + modifier onlyContractSubjectOwner(uint256 subjectTokenId) { + LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); + IERC721 subjectContract = IERC721(istore.ContractERC721Address); + require( + msg.sender == subjectContract.ownerOf(subjectTokenId), + "InventoryFacet.getSubjectTokenSlots: Message sender is not owner of subject token" ); _; } @@ -133,7 +133,6 @@ contract InventoryFacet is ) external onlyAdmin - requireValidSlotType(slotType) returns (uint256) { @@ -143,10 +142,9 @@ contract InventoryFacet is // Slots are 1-indexed! istore.NumSlots += 1; uint256 newSlot = istore.NumSlots; - // save the slot type! istore.SlotData[newSlot] = LibInventory.Slot({ - slotType: LibInventory.SlotType(slotType), + SlotType: slotType, SlotURI: slotURI, SlotIsUnequippable: unequippable, SlotId: newSlot @@ -156,7 +154,22 @@ contract InventoryFacet is return newSlot; } - function assignSlotToSubjectTokenId(uint256 toSubjectTokenId, uint256 slotId) external onlyAdmin { + function setSlotType(uint256 slotType, string memory slotTypeName) external onlyAdmin { + LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); + istore.SlotTypes[slotType] = slotTypeName; + emit NewSlotTypeAdded(msg.sender, slotType, slotTypeName); + } + + function getSlotType(uint256 slotType) external view returns(string memory slotTypeName) { + LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); + return istore.SlotTypes[slotType]; + } + + function addExtraSlotToSubjectTokenId( + uint256 toSubjectTokenId, + uint256 slotId + ) external onlyAdmin + requireSubjectBlacklistedForSlot(toSubjectTokenId, slotId) { LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); LibInventory.Slot memory slotData = istore.SlotData[slotId]; @@ -169,13 +182,10 @@ contract InventoryFacet is ); } - function getSubjectTokenSlots(uint256 subjectTokenId) external view returns(LibInventory.Slot[] memory slots) { + function getSubjectTokenSlots( + uint256 subjectTokenId + ) external view onlyContractSubjectOwner(subjectTokenId) returns(LibInventory.Slot[] memory slots) { LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); - IERC721 subjectContract = IERC721(istore.ContractERC721Address); - require( - msg.sender == subjectContract.ownerOf(subjectTokenId), - "InventoryFacet.getSubjectTokenSlots: Message sender is not owner of subject token" - ); return istore.SubjectSlots[istore.ContractERC721Address][subjectTokenId]; } @@ -187,7 +197,7 @@ contract InventoryFacet is function getSlotById(uint256 subjectTokenId, uint slotId) external view - // @TODO: @ogarciarevett add slotOwner modifier + onlyAdmin returns (LibInventory.Slot memory slot) { return LibInventory.inventoryStorage().SlotData[slotId]; diff --git a/contracts/interfaces/IInventory.sol b/contracts/interfaces/IInventory.sol index 468eddb..9752eb6 100644 --- a/contracts/interfaces/IInventory.sol +++ b/contracts/interfaces/IInventory.sol @@ -15,6 +15,8 @@ interface IInventory { event SlotCreated(address indexed creator, uint256 slot, bool unequippable); + event NewSlotTypeAdded(address indexed creator, uint256 indexed slotType, string slotTypeName); + event ItemMarkedAsEquippableInSlot( uint256 indexed slot, uint256 indexed itemType, @@ -110,7 +112,11 @@ interface IInventory { view returns(LibInventory.Slot[] memory slot); - function assignSlotToSubjectTokenId(uint256 toSubjectTokenId, uint256 slotId) external; + function addExtraSlotToSubjectTokenId(uint256 toSubjectTokenId, uint256 slotId) external; function getSlotURI(uint256 slotId) external view returns (string memory); + + function setSlotType(uint256 slotType, string memory slotTypeName) external; + + function getSlotType(uint256 slotType) external view returns(string memory slotTypeName); } \ No newline at end of file diff --git a/contracts/libraries/LibInventory.sol b/contracts/libraries/LibInventory.sol index ab04b5b..557e629 100644 --- a/contracts/libraries/LibInventory.sol +++ b/contracts/libraries/LibInventory.sol @@ -13,25 +13,9 @@ library LibInventory { uint256 constant ERC721_ITEM_TYPE = 721; uint256 constant ERC1155_ITEM_TYPE = 1155; - // Returns uint - // Unknown - 0 - // Clothes - 1 - // Accesories - 2 - // Materials - 3 - // Badges - 4 - // Trophies - 5 - enum SlotType { - Unknown, - Clothes, - Accesories, - Materials, - Badges, - Trophies - } - struct Slot { string SlotURI; - SlotType slotType; + uint256 SlotType; bool SlotIsUnequippable; uint256 SlotId; } @@ -54,6 +38,10 @@ library LibInventory { mapping(uint256 => Slot) SlotData; + // SlotType => "slot type name" + mapping(uint256 => string) SlotTypes; + + // Slot => item type => item address => item pool ID => maximum equippable // For ERC20 and ERC721 tokens, item pool ID is assumed to be 0. No data will be stored under positive // item pool IDs. @@ -80,10 +68,13 @@ library LibInventory { // EquippedItem struct mapping(address => mapping(uint256 => mapping(uint256 => EquippedItem))) EquippedItems; - // ERC721 Contract Address => - // subjectTokenId => - // slots + // Subject contract address => subject token ID => slotId => Slot[] mapping(address => mapping(uint256 => Slot[])) SubjectSlots; + + // Subject contract address => subject token ID => slotId => bool + mapping(address => mapping(uint256 => mapping(uint256 => bool))) IsSubjectTokenBlackListedForSlot; + + } function inventoryStorage() diff --git a/game7ctl/game7ctl/cli.py b/game7ctl/game7ctl/cli.py index 8f4fa5f..c051e88 100644 --- a/game7ctl/game7ctl/cli.py +++ b/game7ctl/game7ctl/cli.py @@ -20,6 +20,9 @@ def generate_cli() -> argparse.ArgumentParser: subparsers = parser.add_subparsers() core_parser = core_generate_cli() + # TODO: @ogarciarevett rename this: final result should be like: + # game7ctl dao inventory, game7ctl dao achievement, game7ctl dao avatar + # Issue #39 subparsers.add_parser("core", parents=[core_parser], add_help=False) inventory_parser = inventory_generate_cli() diff --git a/game7ctl/game7ctl/core.py b/game7ctl/game7ctl/core.py index 8ae44af..2697973 100644 --- a/game7ctl/game7ctl/core.py +++ b/game7ctl/game7ctl/core.py @@ -2,7 +2,6 @@ import json import os import sys -import time from enum import Enum from typing import Any, Callable, Dict, List, Optional, Set @@ -182,7 +181,7 @@ def facet_cut( return transaction -def diamond_gogogo( +def diamond( owner_address: str, transaction_config: Dict[str, Any], diamond_cut_address: Optional[str] = None, @@ -280,7 +279,7 @@ def diamond_gogogo( return result -def contracts( +def dao( admin_terminus_address: str, admin_terminus_pool_id: int, subject_erc721_address: str, @@ -296,7 +295,7 @@ def contracts( Returns the addresses and attachments. """ - deployment_info = diamond_gogogo( + deployment_info = diamond( owner_address=transaction_config["from"].address, transaction_config=transaction_config, diamond_cut_address=diamond_cut_address, @@ -353,7 +352,7 @@ def handle_facet_cut(args: argparse.Namespace) -> None: ) -def handle_contracts(args: argparse.Namespace) -> None: +def handle_dao(args: argparse.Namespace) -> None: network.connect(args.network) transaction_config = InventoryFacet.get_transaction_config(args) result = contracts( @@ -432,7 +431,7 @@ def generate_cli(): facet_cut_parser.set_defaults(func=handle_facet_cut) contracts_parser = subcommands.add_parser( - "contracts", + "dao", description="Deploy G7 diamond contract", ) Diamond.add_default_arguments(contracts_parser, transact=True) @@ -489,6 +488,6 @@ def generate_cli(): default=None, help="(Optional) file to write deployed addresses to", ) - contracts_parser.set_defaults(func=handle_contracts) + contracts_parser.set_defaults(func=handle_dao) return parser diff --git a/game7ctl/game7ctl/test_inventory.py b/game7ctl/game7ctl/test_inventory.py index fa04f75..e412be4 100644 --- a/game7ctl/game7ctl/test_inventory.py +++ b/game7ctl/game7ctl/test_inventory.py @@ -6,7 +6,7 @@ from moonworm.watch import _fetch_events_chunk from . import InventoryFacet, MockERC20, MockERC721, MockTerminus, inventory_events -from .core import contracts +from .core import dao MAX_UINT = 2**256 - 1 @@ -54,7 +54,7 @@ def setUpClass(cls) -> None: ) cls.predeployment_block = len(chain) - cls.deployed_contracts = contracts( + cls.deployed_contracts = dao( cls.terminus.address, cls.admin_terminus_pool_id, cls.nft.address, From 315b2f23e0e2e753b6360192cd0ae6805d51eb37 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Mon, 30 Jan 2023 20:48:30 -0300 Subject: [PATCH 13/14] feat(inventory): Add minimal backpack functionality + add more tests --- .eslintrc | 17 + .prettierrc | 14 + contracts/facets/InventoryFacet.sol | 54 +- contracts/interfaces/IInventory.sol | 9 +- contracts/libraries/LibInventory.sol | 5 +- game7ctl/game7ctl/InventoryFacet.py | 121 +++-- game7ctl/game7ctl/test_inventory.py | 134 +++++ package.json | 18 + pnpm-lock.yaml | 713 +++++++++++++++++++++++++++ 9 files changed, 1028 insertions(+), 57 deletions(-) create mode 100644 .eslintrc create mode 100644 .prettierrc create mode 100644 package.json create mode 100644 pnpm-lock.yaml diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..579c674 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,17 @@ +{ + "root": true, + "extends": ["eslint:recommended", "prettier"], + "env": { + "es2022": true, + "browser": true, + "node": true, + "mocha": true + }, + "globals": { + "artifacts": "readonly", + "contract": "readonly", + "web3": "readonly", + "extendEnvironment": "readonly", + "expect": "readonly" + } +} diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..e08e242 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,14 @@ +{ + "printWidth": 120, + "singleQuote": true, + "trailingComma": "all", + "arrowParens": "avoid", + "overrides": [ + { + "files": "*.sol", + "options": { + "singleQuote": false + } + } + ] +} diff --git a/contracts/facets/InventoryFacet.sol b/contracts/facets/InventoryFacet.sol index 7a589a5..3459c7f 100644 --- a/contracts/facets/InventoryFacet.sol +++ b/contracts/facets/InventoryFacet.sol @@ -74,16 +74,6 @@ contract InventoryFacet is _; } - modifier requireSubjectBlacklistedForSlot(uint256 toSubjectTokenId, uint256 slotId) { - LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); - - require( - istore.IsSubjectTokenBlackListedForSlot[istore.ContractERC721Address][toSubjectTokenId][slotId] == true, - "InventoryFacet.requireSubjectWhitelistedForSlot: The subject is not in the whitelist for this slot" - ); - _; - } - modifier onlyContractSubjectOwner(uint256 subjectTokenId) { LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); IERC721 subjectContract = IERC721(istore.ContractERC721Address); @@ -165,20 +155,40 @@ contract InventoryFacet is return istore.SlotTypes[slotType]; } - function addExtraSlotToSubjectTokenId( + function addBackPackToSubject( + uint256 slotQty, uint256 toSubjectTokenId, - uint256 slotId - ) external onlyAdmin - requireSubjectBlacklistedForSlot(toSubjectTokenId, slotId) { - LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); + uint256 slotType, + string memory slotURI + ) external onlyAdmin { + + require( + slotQty > 0, + "InventoryFacet.addBackPackToSubject: Slot quantity must be greater than 0" + ); - LibInventory.Slot memory slotData = istore.SlotData[slotId]; + LibInventory.InventoryStorage storage istore = LibInventory.inventoryStorage(); - istore.SubjectSlots[istore.ContractERC721Address][toSubjectTokenId].push(slotData); + uint256 previousSlotNumSubject = istore.SubjectSlots[istore.ContractERC721Address][toSubjectTokenId].length; + + for (uint256 i = 0; i < slotQty; i++) { + istore.SubjectSlots[istore.ContractERC721Address][toSubjectTokenId].push( + LibInventory.Slot({ + SlotType: slotType, + SlotURI: slotURI, + SlotIsUnequippable: false, + // previousSlotNumSubject = 3 + // previousSlotNumSubject + i = 3;(first iteration) + // previousSlotNumSubject + 1 = 4; + SlotId: previousSlotNumSubject + i == previousSlotNumSubject ? previousSlotNumSubject + 1: previousSlotNumSubject + i + }) + ); + } - emit AssignSlotToSubjectTokenId( + emit BackpackAdded( + msg.sender, toSubjectTokenId, - slotId + slotQty ); } @@ -216,6 +226,7 @@ contract InventoryFacet is LibInventory.Slot memory slot = istore.SlotData[slotId]; slot.SlotURI = newSlotURI; + istore.SlotData[slotId] = slot; emit NewSlotURI(slotId); } @@ -223,11 +234,6 @@ contract InventoryFacet is return LibInventory.inventoryStorage().SlotData[slotId].SlotIsUnequippable; } - // TODO: @ogarciarevett remove this, is already in the Slot struct - // function _slotIsUnequippable(uint256 slot) external view returns (bool) { - // return LibInventory.inventoryStorage().SlotIsUnequippable[slot]; - // } - function markItemAsEquippableInSlot( uint256 slot, uint256 itemType, diff --git a/contracts/interfaces/IInventory.sol b/contracts/interfaces/IInventory.sol index 9752eb6..590623e 100644 --- a/contracts/interfaces/IInventory.sol +++ b/contracts/interfaces/IInventory.sol @@ -25,7 +25,7 @@ interface IInventory { uint256 maxAmount ); - event AssignSlotToSubjectTokenId(uint indexed toSubjectTokenId, uint256 indexed slotId); + event BackpackAdded(address indexed creator, uint indexed toSubjectTokenId, uint256 indexed slotQuantity); event NewSlotURI(uint indexed slotId); @@ -112,7 +112,12 @@ interface IInventory { view returns(LibInventory.Slot[] memory slot); - function addExtraSlotToSubjectTokenId(uint256 toSubjectTokenId, uint256 slotId) external; + function addBackPackToSubject( + uint256 slotQty, + uint256 toSubjectTokenId, + uint256 slotType, + string memory slotURI + ) external; function getSlotURI(uint256 slotId) external view returns (string memory); diff --git a/contracts/libraries/LibInventory.sol b/contracts/libraries/LibInventory.sol index 557e629..3f5bc44 100644 --- a/contracts/libraries/LibInventory.sol +++ b/contracts/libraries/LibInventory.sol @@ -68,9 +68,12 @@ library LibInventory { // EquippedItem struct mapping(address => mapping(uint256 => mapping(uint256 => EquippedItem))) EquippedItems; - // Subject contract address => subject token ID => slotId => Slot[] + // Subject contract address => subject token ID => Slot[] mapping(address => mapping(uint256 => Slot[])) SubjectSlots; + // Subject contract address => subject token ID => slotNum + mapping(address => mapping(uint256 => uint256)) SubjectNumSlots; + // Subject contract address => subject token ID => slotId => bool mapping(address => mapping(uint256 => mapping(uint256 => bool))) IsSubjectTokenBlackListedForSlot; diff --git a/game7ctl/game7ctl/InventoryFacet.py b/game7ctl/game7ctl/InventoryFacet.py index 53c3f6e..d4344c0 100644 --- a/game7ctl/game7ctl/InventoryFacet.py +++ b/game7ctl/game7ctl/InventoryFacet.py @@ -96,19 +96,24 @@ def verify_contract(self): contract_class = contract_from_build(self.contract_name) contract_class.publish_source(self.contract) - def admin_terminus_info( - self, block_number: Optional[Union[str, int]] = "latest" + def add_back_pack_to_subject( + self, + slot_qty: int, + to_subject_token_id: int, + slot_type: int, + slot_uri: str, + transaction_config, ) -> Any: self.assert_contract_is_instantiated() - return self.contract.adminTerminusInfo.call(block_identifier=block_number) + return self.contract.addBackPackToSubject( + slot_qty, to_subject_token_id, slot_type, slot_uri, transaction_config + ) - def assign_slot_to_subject_token_id( - self, to_subject_token_id: int, slot_id: int, transaction_config + def admin_terminus_info( + self, block_number: Optional[Union[str, int]] = "latest" ) -> Any: self.assert_contract_is_instantiated() - return self.contract.assignSlotToSubjectTokenId( - to_subject_token_id, slot_id, transaction_config - ) + return self.contract.adminTerminusInfo.call(block_identifier=block_number) def create_slot( self, unequippable: bool, slot_type: int, slot_uri: str, transaction_config @@ -161,6 +166,12 @@ def get_slot_by_id( subject_token_id, slot_id, block_identifier=block_number ) + def get_slot_type( + self, slot_type: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.getSlotType.call(slot_type, block_identifier=block_number) + def get_slot_uri( self, slot_id: int, block_number: Optional[Union[str, int]] = "latest" ) -> Any: @@ -262,6 +273,12 @@ def on_erc721_received( arg1, arg2, arg3, arg4, transaction_config ) + def set_slot_type( + self, slot_type: int, slot_type_name: str, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setSlotType(slot_type, slot_type_name, transaction_config) + def set_slot_uri(self, new_slot_uri: str, slot_id: int, transaction_config) -> Any: self.assert_contract_is_instantiated() return self.contract.setSlotUri(new_slot_uri, slot_id, transaction_config) @@ -384,20 +401,15 @@ def handle_verify_contract(args: argparse.Namespace) -> None: print(result) -def handle_admin_terminus_info(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = InventoryFacet(args.address) - result = contract.admin_terminus_info(block_number=args.block_number) - print(result) - - -def handle_assign_slot_to_subject_token_id(args: argparse.Namespace) -> None: +def handle_add_back_pack_to_subject(args: argparse.Namespace) -> None: network.connect(args.network) contract = InventoryFacet(args.address) transaction_config = get_transaction_config(args) - result = contract.assign_slot_to_subject_token_id( + result = contract.add_back_pack_to_subject( + slot_qty=args.slot_qty, to_subject_token_id=args.to_subject_token_id, - slot_id=args.slot_id, + slot_type=args.slot_type, + slot_uri=args.slot_uri, transaction_config=transaction_config, ) print(result) @@ -405,6 +417,13 @@ def handle_assign_slot_to_subject_token_id(args: argparse.Namespace) -> None: print(result.info()) +def handle_admin_terminus_info(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = InventoryFacet(args.address) + result = contract.admin_terminus_info(block_number=args.block_number) + print(result) + + def handle_create_slot(args: argparse.Namespace) -> None: network.connect(args.network) contract = InventoryFacet(args.address) @@ -460,6 +479,15 @@ def handle_get_slot_by_id(args: argparse.Namespace) -> None: print(result) +def handle_get_slot_type(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = InventoryFacet(args.address) + result = contract.get_slot_type( + slot_type=args.slot_type, block_number=args.block_number + ) + print(result) + + def handle_get_slot_uri(args: argparse.Namespace) -> None: network.connect(args.network) contract = InventoryFacet(args.address) @@ -578,6 +606,20 @@ def handle_on_erc721_received(args: argparse.Namespace) -> None: print(result.info()) +def handle_set_slot_type(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = InventoryFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_slot_type( + slot_type=args.slot_type, + slot_type_name=args.slot_type_name, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + def handle_set_slot_uri(args: argparse.Namespace) -> None: network.connect(args.network) contract = InventoryFacet(args.address) @@ -646,23 +688,25 @@ def generate_cli() -> argparse.ArgumentParser: add_default_arguments(verify_contract_parser, False) verify_contract_parser.set_defaults(func=handle_verify_contract) - admin_terminus_info_parser = subcommands.add_parser("admin-terminus-info") - add_default_arguments(admin_terminus_info_parser, False) - admin_terminus_info_parser.set_defaults(func=handle_admin_terminus_info) - - assign_slot_to_subject_token_id_parser = subcommands.add_parser( - "assign-slot-to-subject-token-id" + add_back_pack_to_subject_parser = subcommands.add_parser("add-back-pack-to-subject") + add_default_arguments(add_back_pack_to_subject_parser, True) + add_back_pack_to_subject_parser.add_argument( + "--slot-qty", required=True, help="Type: uint256", type=int ) - add_default_arguments(assign_slot_to_subject_token_id_parser, True) - assign_slot_to_subject_token_id_parser.add_argument( + add_back_pack_to_subject_parser.add_argument( "--to-subject-token-id", required=True, help="Type: uint256", type=int ) - assign_slot_to_subject_token_id_parser.add_argument( - "--slot-id", required=True, help="Type: uint256", type=int + add_back_pack_to_subject_parser.add_argument( + "--slot-type", required=True, help="Type: uint256", type=int ) - assign_slot_to_subject_token_id_parser.set_defaults( - func=handle_assign_slot_to_subject_token_id + add_back_pack_to_subject_parser.add_argument( + "--slot-uri", required=True, help="Type: string", type=str ) + add_back_pack_to_subject_parser.set_defaults(func=handle_add_back_pack_to_subject) + + admin_terminus_info_parser = subcommands.add_parser("admin-terminus-info") + add_default_arguments(admin_terminus_info_parser, False) + admin_terminus_info_parser.set_defaults(func=handle_admin_terminus_info) create_slot_parser = subcommands.add_parser("create-slot") add_default_arguments(create_slot_parser, True) @@ -713,6 +757,13 @@ def generate_cli() -> argparse.ArgumentParser: ) get_slot_by_id_parser.set_defaults(func=handle_get_slot_by_id) + get_slot_type_parser = subcommands.add_parser("get-slot-type") + add_default_arguments(get_slot_type_parser, False) + get_slot_type_parser.add_argument( + "--slot-type", required=True, help="Type: uint256", type=int + ) + get_slot_type_parser.set_defaults(func=handle_get_slot_type) + get_slot_uri_parser = subcommands.add_parser("get-slot-uri") add_default_arguments(get_slot_uri_parser, False) get_slot_uri_parser.add_argument( @@ -841,6 +892,16 @@ def generate_cli() -> argparse.ArgumentParser: ) on_erc721_received_parser.set_defaults(func=handle_on_erc721_received) + set_slot_type_parser = subcommands.add_parser("set-slot-type") + add_default_arguments(set_slot_type_parser, True) + set_slot_type_parser.add_argument( + "--slot-type", required=True, help="Type: uint256", type=int + ) + set_slot_type_parser.add_argument( + "--slot-type-name", required=True, help="Type: string", type=str + ) + set_slot_type_parser.set_defaults(func=handle_set_slot_type) + set_slot_uri_parser = subcommands.add_parser("set-slot-uri") add_default_arguments(set_slot_uri_parser, True) set_slot_uri_parser.add_argument( diff --git a/game7ctl/game7ctl/test_inventory.py b/game7ctl/game7ctl/test_inventory.py index e412be4..471ddc6 100644 --- a/game7ctl/game7ctl/test_inventory.py +++ b/game7ctl/game7ctl/test_inventory.py @@ -181,6 +181,58 @@ def test_admin_can_create_unequippable_slot(self): unequippable, ) + def test_admin_can_add_backpacks_to_subject_token(self): + unequippable = False + subject_token_id = self.nft.total_supply() + self.nft.mint(self.player.address, subject_token_id, {"from": self.owner}) + + # player has 0 slots in their inventory + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) + num_slots_1 = self.inventory.num_slots() + + # all the players has 1 slot in their inventory + self.assertEqual(num_slots_1, 1) + + # admin adds 10 more slots to the subject token + self.inventory.add_back_pack_to_subject( + 10, + subject_token_id, + 0, + "some_fancy_slot_uri", + transaction_config={"from": self.admin}, + ) + + # all the players still having only 1 slot in their inventory + self.assertEqual(num_slots_1, 1) + + def test_admin_can_set_slot_uri(self): + unequippable = False + + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) + num_slots_1 = self.inventory.num_slots() + + # set the slot uri + self.inventory.set_slot_uri( + "some_fancy_slot_uri", + num_slots_1, + transaction_config={"from": self.admin}, + ) + + new_slot_uri = self.inventory.get_slot_uri(num_slots_1) + + # the slot uri is updated + self.assertEqual(new_slot_uri, "some_fancy_slot_uri") + def test_nonadmin_cannot_create_slot(self): unequippable = False @@ -196,6 +248,88 @@ def test_nonadmin_cannot_create_slot(self): self.assertEqual(num_slots_1, num_slots_0) + def test_noadmin_cannot_set_slot_uri(self): + unequippable = False + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) + num_slots_0 = self.inventory.num_slots() + + # set the slot uri + with self.assertRaises(VirtualMachineError): + self.inventory.set_slot_uri( + "some_fancy_slot_uri", + 1, + transaction_config={"from": self.player}, + ) + + num_slots_1 = self.inventory.num_slots() + + self.assertEqual(num_slots_1, num_slots_0) + + def test_admin_cannot_get_subject_slots(self): + unequippable = False + subject_token_id = self.nft.total_supply() + self.nft.mint(self.player.address, subject_token_id, {"from": self.owner}) + + # player has 0 slots in their inventory + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) + num_slots_0 = self.inventory.num_slots() + + # admin adds 10 more slots to the subject token + self.inventory.add_back_pack_to_subject( + 10, + subject_token_id, + 0, + "some_fancy_slot_uri", + transaction_config={"from": self.admin}, + ) + + # set the slot uri + with self.assertRaises(VirtualMachineError): + self.inventory.get_subject_token_slots(subject_token_id) + + num_slots_1 = self.inventory.num_slots() + + self.assertEqual(num_slots_1, num_slots_0) + + def test_noadmin_cannot_add_backpack_to_subject(self): + unequippable = False + subject_token_id = self.nft.total_supply() + self.nft.mint(self.player.address, subject_token_id, {"from": self.owner}) + + # player has 0 slots in their inventory + self.inventory.create_slot( + unequippable, + slot_type=1, + slot_uri="random_uri", + transaction_config={"from": self.admin}, + ) + num_slots_0 = self.inventory.num_slots() + + # set the slot uri + with self.assertRaises(VirtualMachineError): + # admin adds 10 more slots to the subject token + self.inventory.add_back_pack_to_subject( + 10, + subject_token_id, + 0, + "some_fancy_slot_uri", + transaction_config={"from": self.player}, + ) + + num_slots_1 = self.inventory.num_slots() + + self.assertEqual(num_slots_1, num_slots_0) + def test_admin_cannot_mark_contracts_with_invalid_type_as_eligible_for_slots( self, ): diff --git a/package.json b/package.json new file mode 100644 index 0000000..026b392 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "contracts", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "eslint": "^8.33.0", + "eslint-config-prettier": "^8.6.0", + "prettier": "^2.8.3", + "prettier-plugin-solidity": "^1.1.1" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..84cfe62 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,713 @@ +lockfileVersion: 5.4 + +specifiers: + eslint: ^8.33.0 + eslint-config-prettier: ^8.6.0 + prettier: ^2.8.3 + prettier-plugin-solidity: ^1.1.1 + +devDependencies: + eslint: 8.33.0 + eslint-config-prettier: 8.6.0_eslint@8.33.0 + prettier: 2.8.3 + prettier-plugin-solidity: 1.1.1_prettier@2.8.3 + +packages: + + /@eslint/eslintrc/1.4.1: + resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.4.1 + globals: 13.20.0 + ignore: 5.2.4 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/config-array/0.11.8: + resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/module-importer/1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema/1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + dev: true + + /@nodelib/fs.scandir/2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat/2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk/1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@solidity-parser/parser/0.14.5: + resolution: {integrity: sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==} + dependencies: + antlr4ts: 0.5.0-alpha.4 + dev: true + + /acorn-jsx/5.3.2_acorn@8.8.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.8.2 + dev: true + + /acorn/8.8.2: + resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /ajv/6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /ansi-regex/5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-styles/4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /antlr4ts/0.5.0-alpha.4: + resolution: {integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==} + dev: true + + /argparse/2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /balanced-match/1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /brace-expansion/1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /callsites/3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /chalk/4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /color-convert/2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name/1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /concat-map/0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /cross-spawn/7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /debug/4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /deep-is/0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /doctrine/3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /escape-string-regexp/4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-config-prettier/8.6.0_eslint@8.33.0: + resolution: {integrity: sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.33.0 + dev: true + + /eslint-scope/7.1.1: + resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-utils/3.0.0_eslint@8.33.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint: 8.33.0 + eslint-visitor-keys: 2.1.0 + dev: true + + /eslint-visitor-keys/2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + dev: true + + /eslint-visitor-keys/3.3.0: + resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint/8.33.0: + resolution: {integrity: sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': 1.4.1 + '@humanwhocodes/config-array': 0.11.8 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.1.1 + eslint-utils: 3.0.0_eslint@8.33.0 + eslint-visitor-keys: 3.3.0 + espree: 9.4.1 + esquery: 1.4.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.20.0 + grapheme-splitter: 1.0.4 + ignore: 5.2.4 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-sdsl: 4.3.0 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.1 + regexpp: 3.2.0 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree/9.4.1: + resolution: {integrity: sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.8.2 + acorn-jsx: 5.3.2_acorn@8.8.2 + eslint-visitor-keys: 3.3.0 + dev: true + + /esquery/1.4.0: + resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse/4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse/5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /esutils/2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /fast-deep-equal/3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-json-stable-stringify/2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein/2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true + + /fastq/1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /file-entry-cache/6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.0.4 + dev: true + + /find-up/5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat-cache/3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.7 + rimraf: 3.0.2 + dev: true + + /flatted/3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + dev: true + + /fs.realpath/1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /glob-parent/6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob/7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /globals/13.20.0: + resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /grapheme-splitter/1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + dev: true + + /has-flag/4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /ignore/5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /import-fresh/3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /imurmurhash/0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /inflight/1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits/2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /is-extglob/2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-glob/4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-path-inside/3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /isexe/2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /js-sdsl/4.3.0: + resolution: {integrity: sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==} + dev: true + + /js-yaml/4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /json-schema-traverse/0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-stable-stringify-without-jsonify/1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true + + /levn/0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /locate-path/6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.merge/4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lru-cache/6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /minimatch/3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /ms/2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /natural-compare/1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true + + /once/1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /optionator/0.9.1: + resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.3 + dev: true + + /p-limit/3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate/5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /parent-module/1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /path-exists/4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute/1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key/3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /prelude-ls/1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prettier-plugin-solidity/1.1.1_prettier@2.8.3: + resolution: {integrity: sha512-uD24KO26tAHF+zMN2nt1OUzfknzza5AgxjogQQrMLZc7j8xiQrDoNWNeOlfFC0YLTwo12CLD10b9niLyP6AqXg==} + engines: {node: '>=12'} + peerDependencies: + prettier: '>=2.3.0 || >=3.0.0-alpha.0' + dependencies: + '@solidity-parser/parser': 0.14.5 + prettier: 2.8.3 + semver: 7.3.8 + solidity-comments-extractor: 0.0.7 + dev: true + + /prettier/2.8.3: + resolution: {integrity: sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==} + engines: {node: '>=10.13.0'} + hasBin: true + dev: true + + /punycode/2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + dev: true + + /queue-microtask/1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /regexpp/3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + dev: true + + /resolve-from/4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /reusify/1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rimraf/3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /run-parallel/1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /semver/7.3.8: + resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /shebang-command/2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex/3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /solidity-comments-extractor/0.0.7: + resolution: {integrity: sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==} + dev: true + + /strip-ansi/6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-json-comments/3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /supports-color/7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /text-table/0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /type-check/0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-fest/0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /uri-js/4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.0 + dev: true + + /which/2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /word-wrap/1.2.3: + resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} + engines: {node: '>=0.10.0'} + dev: true + + /wrappy/1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /yallist/4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yocto-queue/0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true From 8cb4c234404550172246adabf53a3cdcaf0fe296 Mon Sep 17 00:00:00 2001 From: Omar Garcia <12629920+ogarciarevett@users.noreply.github.com> Date: Mon, 30 Jan 2023 21:20:50 -0300 Subject: [PATCH 14/14] fix(inventory): Fix test ref --- game7ctl/game7ctl/test_inventory.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/game7ctl/game7ctl/test_inventory.py b/game7ctl/game7ctl/test_inventory.py index 471ddc6..536c32e 100644 --- a/game7ctl/game7ctl/test_inventory.py +++ b/game7ctl/game7ctl/test_inventory.py @@ -6,7 +6,7 @@ from moonworm.watch import _fetch_events_chunk from . import InventoryFacet, MockERC20, MockERC721, MockTerminus, inventory_events -from .core import dao +from .core import systems MAX_UINT = 2**256 - 1 @@ -54,7 +54,7 @@ def setUpClass(cls) -> None: ) cls.predeployment_block = len(chain) - cls.deployed_contracts = dao( + cls.deployed_contracts = systems( cls.terminus.address, cls.admin_terminus_pool_id, cls.nft.address,