From 8a990e81f8bc2d4834469d940e6fd35587177f26 Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Sun, 20 Aug 2023 17:45:17 -0700 Subject: [PATCH 01/12] Brought `cli/test.sh` from `statblock` branch --- cli/test.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/test.sh b/cli/test.sh index 7196e8dc..75550a51 100755 --- a/cli/test.sh +++ b/cli/test.sh @@ -26,7 +26,8 @@ fi TEST_COMMAND=${@:-discover} -cd .. +SCRIPT_DIR=$(realpath $(dirname $0)) +cd $SCRIPT_DIR/.. brownie compile cd - set -x From 97f9f28021ac21462feb8ab6ec0bd0bca85a6703 Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Sun, 20 Aug 2023 17:48:08 -0700 Subject: [PATCH 02/12] Added all Terminus-related solidity code... Migrated from https://github.com/bugout-dev/dao At commit: `0a587314790dc1285351abe2072d476cdf9521d5` --- .../terminus/ERC1155WithTerminusStorage.sol | 638 ++++++++++++++++++ contracts/terminus/LibTerminus.sol | 131 ++++ contracts/terminus/TerminusFacet.sol | 336 +++++++++ contracts/terminus/TerminusInitializer.sol | 27 + contracts/terminus/TerminusPermissions.sol | 41 ++ .../controller/LibTerminusController.sol | 36 + .../controller/TerminusControllerFacet.sol | 272 ++++++++ 7 files changed, 1481 insertions(+) create mode 100644 contracts/terminus/ERC1155WithTerminusStorage.sol create mode 100644 contracts/terminus/LibTerminus.sol create mode 100644 contracts/terminus/TerminusFacet.sol create mode 100644 contracts/terminus/TerminusInitializer.sol create mode 100644 contracts/terminus/TerminusPermissions.sol create mode 100644 contracts/terminus/controller/LibTerminusController.sol create mode 100644 contracts/terminus/controller/TerminusControllerFacet.sol diff --git a/contracts/terminus/ERC1155WithTerminusStorage.sol b/contracts/terminus/ERC1155WithTerminusStorage.sol new file mode 100644 index 00000000..b01dc7a2 --- /dev/null +++ b/contracts/terminus/ERC1155WithTerminusStorage.sol @@ -0,0 +1,638 @@ +// SPDX-License-Identifier: Apache-2.0 + +/** + * Authors: Moonstream Engineering (engineering@moonstream.to) + * GitHub: https://github.com/bugout-dev/dao + * + * An ERC1155 implementation which uses the Moonstream DAO common storage structure for proxies. + * EIP1155: https://eips.ethereum.org/EIPS/eip-1155 + * + * The Moonstream contract is used to delegate calls from an EIP2535 Diamond proxy. + * + * This implementation is adapted from the OpenZeppelin ERC1155 implementation: + * https://github.com/OpenZeppelin/openzeppelin-contracts/tree/6bd6b76d1156e20e45d1016f355d154141c7e5b9/contracts/token/ERC1155 + */ + +pragma solidity ^0.8.9; + +import "@openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol"; +import "@openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol"; +import "@openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol"; +import "@openzeppelin-contracts/contracts/utils/Address.sol"; +import "@openzeppelin-contracts/contracts/utils/Context.sol"; +import "@openzeppelin-contracts/contracts/utils/introspection/ERC165.sol"; +import "./LibTerminus.sol"; + +contract ERC1155WithTerminusStorage is + Context, + ERC165, + IERC1155, + IERC1155MetadataURI +{ + using Address for address; + + constructor() {} + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(ERC165, IERC165) + returns (bool) + { + return + interfaceId == type(IERC1155).interfaceId || + interfaceId == type(IERC1155MetadataURI).interfaceId || + super.supportsInterface(interfaceId); + } + + function uri(uint256 poolID) + public + view + virtual + override + returns (string memory) + { + return LibTerminus.terminusStorage().poolURI[poolID]; + } + + /** + * @dev See {IERC1155-balanceOf}. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) + public + view + virtual + override + returns (uint256) + { + require( + account != address(0), + "ERC1155WithTerminusStorage: balance query for the zero address" + ); + return LibTerminus.terminusStorage().poolBalances[id][account]; + } + + /** + * @dev See {IERC1155-balanceOfBatch}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch(address[] memory accounts, uint256[] memory ids) + public + view + virtual + override + returns (uint256[] memory) + { + require( + accounts.length == ids.length, + "ERC1155WithTerminusStorage: accounts and ids length mismatch" + ); + + uint256[] memory batchBalances = new uint256[](accounts.length); + + for (uint256 i = 0; i < accounts.length; ++i) { + batchBalances[i] = balanceOf(accounts[i], ids[i]); + } + + return batchBalances; + } + + /** + * @dev See {IERC1155-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) + public + virtual + override + { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC1155-isApprovedForAll}. + */ + function isApprovedForAll(address account, address operator) + public + view + virtual + override + returns (bool) + { + return + LibTerminus.terminusStorage().globalOperatorApprovals[account][ + operator + ]; + } + + function isApprovedForPool(uint256 poolID, address operator) + public + view + returns (bool) + { + return LibTerminus._isApprovedForPool(poolID, operator); + } + + function approveForPool(uint256 poolID, address operator) external { + LibTerminus.enforcePoolIsController(poolID, _msgSender()); + LibTerminus._approveForPool(poolID, operator); + } + + function unapproveForPool(uint256 poolID, address operator) external { + LibTerminus.enforcePoolIsController(poolID, _msgSender()); + LibTerminus._unapproveForPool(poolID, operator); + } + + /** + * @dev See {IERC1155-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) public virtual override { + require( + from == _msgSender() || + isApprovedForAll(from, _msgSender()) || + isApprovedForPool(id, _msgSender()), + "ERC1155WithTerminusStorage: caller is not owner nor approved" + ); + _safeTransferFrom(from, to, id, amount, data); + } + + /** + * @dev See {IERC1155-safeBatchTransferFrom}. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) public virtual override { + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()), + "ERC1155WithTerminusStorage: transfer caller is not owner nor approved" + ); + _safeBatchTransferFrom(from, to, ids, amounts, data); + } + + /** + * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `from` must have a balance of tokens of type `id` of at least `amount`. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual { + require( + to != address(0), + "ERC1155WithTerminusStorage: transfer to the zero address" + ); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + require( + !ts.poolNotTransferable[id], + "ERC1155WithTerminusStorage: _safeTransferFrom -- pool is not transferable" + ); + + address operator = _msgSender(); + + _beforeTokenTransfer( + operator, + from, + to, + _asSingletonArray(id), + _asSingletonArray(amount), + data + ); + + uint256 fromBalance = ts.poolBalances[id][from]; + require( + fromBalance >= amount, + "ERC1155WithTerminusStorage: insufficient balance for transfer" + ); + unchecked { + ts.poolBalances[id][from] = fromBalance - amount; + } + ts.poolBalances[id][to] += amount; + + emit TransferSingle(operator, from, to, id, amount); + + _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require( + ids.length == amounts.length, + "ERC1155WithTerminusStorage: ids and amounts length mismatch" + ); + require( + to != address(0), + "ERC1155WithTerminusStorage: transfer to the zero address" + ); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, to, ids, amounts, data); + + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + require( + !ts.poolNotTransferable[id], + "ERC1155WithTerminusStorage: _safeBatchTransferFrom -- pool is not transferable" + ); + + uint256 fromBalance = ts.poolBalances[id][from]; + require( + fromBalance >= amount, + "ERC1155WithTerminusStorage: insufficient balance for transfer" + ); + unchecked { + ts.poolBalances[id][from] = fromBalance - amount; + } + ts.poolBalances[id][to] += amount; + } + + emit TransferBatch(operator, from, to, ids, amounts); + + _doSafeBatchTransferAcceptanceCheck( + operator, + from, + to, + ids, + amounts, + data + ); + } + + /** + * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _mint( + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual { + require( + to != address(0), + "ERC1155WithTerminusStorage: mint to the zero address" + ); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + require( + ts.poolSupply[id] + amount <= ts.poolCapacity[id], + "ERC1155WithTerminusStorage: _mint -- Minted tokens would exceed pool capacity" + ); + + address operator = _msgSender(); + + _beforeTokenTransfer( + operator, + address(0), + to, + _asSingletonArray(id), + _asSingletonArray(amount), + data + ); + + ts.poolSupply[id] += amount; + ts.poolBalances[id][to] += amount; + emit TransferSingle(operator, address(0), to, id, amount); + + _doSafeTransferAcceptanceCheck( + operator, + address(0), + to, + id, + amount, + data + ); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _mintBatch( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require( + to != address(0), + "ERC1155WithTerminusStorage: mint to the zero address" + ); + require( + ids.length == amounts.length, + "ERC1155WithTerminusStorage: ids and amounts length mismatch" + ); + + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); + + for (uint256 i = 0; i < ids.length; i++) { + require( + ts.poolSupply[ids[i]] + amounts[i] <= ts.poolCapacity[ids[i]], + "ERC1155WithTerminusStorage: _mintBatch -- Minted tokens would exceed pool capacity" + ); + ts.poolSupply[ids[i]] += amounts[i]; + ts.poolBalances[ids[i]][to] += amounts[i]; + } + + emit TransferBatch(operator, address(0), to, ids, amounts); + + _doSafeBatchTransferAcceptanceCheck( + operator, + address(0), + to, + ids, + amounts, + data + ); + } + + /** + * @dev Destroys `amount` tokens of token type `id` from `from` + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `from` must have at least `amount` tokens of token type `id`. + */ + function _burn( + address from, + uint256 id, + uint256 amount + ) internal virtual { + require( + from != address(0), + "ERC1155WithTerminusStorage: burn from the zero address" + ); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + require( + ts.poolBurnable[id], + "ERC1155WithTerminusStorage: _burn -- pool is not burnable" + ); + + address operator = _msgSender(); + + _beforeTokenTransfer( + operator, + from, + address(0), + _asSingletonArray(id), + _asSingletonArray(amount), + "" + ); + + uint256 fromBalance = ts.poolBalances[id][from]; + require( + fromBalance >= amount, + "ERC1155WithTerminusStorage: burn amount exceeds balance" + ); + unchecked { + ts.poolBalances[id][from] = fromBalance - amount; + ts.poolSupply[id] -= amount; + } + + emit TransferSingle(operator, from, address(0), id, amount); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + */ + function _burnBatch( + address from, + uint256[] memory ids, + uint256[] memory amounts + ) internal virtual { + require( + from != address(0), + "ERC1155WithTerminusStorage: burn from the zero address" + ); + require( + ids.length == amounts.length, + "ERC1155WithTerminusStorage: ids and amounts length mismatch" + ); + + address operator = _msgSender(); + + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + for (uint256 i = 0; i < ids.length; i++) { + require( + ts.poolBurnable[ids[i]], + "ERC1155WithTerminusStorage: _burnBatch -- pool is not burnable" + ); + } + + _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); + + for (uint256 i = 0; i < ids.length; i++) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + uint256 fromBalance = ts.poolBalances[id][from]; + require( + fromBalance >= amount, + "ERC1155WithTerminusStorage: burn amount exceeds balance" + ); + unchecked { + ts.poolBalances[id][from] = fromBalance - amount; + ts.poolSupply[id] -= amount; + } + } + + emit TransferBatch(operator, from, address(0), ids, amounts); + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Emits a {ApprovalForAll} event. + */ + function _setApprovalForAll( + address owner, + address operator, + bool approved + ) internal virtual { + require( + owner != operator, + "ERC1155WithTerminusStorage: setting approval status for self" + ); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.globalOperatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `id` and `amount` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual {} + + function _doSafeTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) private { + if (to.isContract()) { + try + IERC1155Receiver(to).onERC1155Received( + operator, + from, + id, + amount, + data + ) + returns (bytes4 response) { + if (response != IERC1155Receiver.onERC1155Received.selector) { + revert( + "ERC1155WithTerminusStorage: ERC1155Receiver rejected tokens" + ); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert( + "ERC1155WithTerminusStorage: transfer to non ERC1155Receiver implementer" + ); + } + } + } + + function _doSafeBatchTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) private { + if (to.isContract()) { + try + IERC1155Receiver(to).onERC1155BatchReceived( + operator, + from, + ids, + amounts, + data + ) + returns (bytes4 response) { + if ( + response != IERC1155Receiver.onERC1155BatchReceived.selector + ) { + revert( + "ERC1155WithTerminusStorage: ERC1155Receiver rejected tokens" + ); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert( + "ERC1155WithTerminusStorage: transfer to non ERC1155Receiver implementer" + ); + } + } + } + + function _asSingletonArray(uint256 element) + private + pure + returns (uint256[] memory) + { + uint256[] memory array = new uint256[](1); + array[0] = element; + + return array; + } +} diff --git a/contracts/terminus/LibTerminus.sol b/contracts/terminus/LibTerminus.sol new file mode 100644 index 00000000..29bd8497 --- /dev/null +++ b/contracts/terminus/LibTerminus.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: Apache-2.0 + +/** + * Authors: Moonstream Engineering (engineering@moonstream.to) + * GitHub: https://github.com/bugout-dev/dao + * + * Common storage structure and internal methods for Moonstream DAO Terminus contracts. + * As Terminus is an extension of ERC1155, this library can also be used to implement bare ERC1155 contracts + * using the common storage pattern (e.g. for use in diamond proxies). + */ + +// TODO(zomglings): Should we support EIP1761 in addition to ERC1155 or roll our own scopes and feature flags? +// https://eips.ethereum.org/EIPS/eip-1761 + +pragma solidity ^0.8.9; + +library LibTerminus { + bytes32 constant TERMINUS_STORAGE_POSITION = + keccak256("moonstreamdao.eth.storage.terminus"); + + struct TerminusStorage { + // Terminus administration + address controller; + bool isTerminusActive; + uint256 currentPoolID; + address paymentToken; + uint256 poolBasePrice; + // Terminus pools + mapping(uint256 => address) poolController; + mapping(uint256 => string) poolURI; + mapping(uint256 => uint256) poolCapacity; + mapping(uint256 => uint256) poolSupply; + mapping(uint256 => mapping(address => uint256)) poolBalances; + mapping(uint256 => bool) poolNotTransferable; + mapping(uint256 => bool) poolBurnable; + mapping(address => mapping(address => bool)) globalOperatorApprovals; + mapping(uint256 => mapping(address => bool)) globalPoolOperatorApprovals; + // Contract metadata + string contractURI; + } + + function terminusStorage() + internal + pure + returns (TerminusStorage storage es) + { + bytes32 position = TERMINUS_STORAGE_POSITION; + assembly { + es.slot := position + } + } + + event ControlTransferred( + address indexed previousController, + address indexed newController + ); + + event PoolControlTransferred( + uint256 indexed poolID, + address indexed previousController, + address indexed newController + ); + + function setController(address newController) internal { + TerminusStorage storage ts = terminusStorage(); + address previousController = ts.controller; + ts.controller = newController; + emit ControlTransferred(previousController, newController); + } + + function enforceIsController() internal view { + TerminusStorage storage ts = terminusStorage(); + require(msg.sender == ts.controller, "LibTerminus: Must be controller"); + } + + function setTerminusActive(bool active) internal { + TerminusStorage storage ts = terminusStorage(); + ts.isTerminusActive = active; + } + + function setPoolController(uint256 poolID, address newController) internal { + TerminusStorage storage ts = terminusStorage(); + address previousController = ts.poolController[poolID]; + ts.poolController[poolID] = newController; + emit PoolControlTransferred(poolID, previousController, newController); + } + + function createSimplePool(uint256 _capacity) internal returns (uint256) { + TerminusStorage storage ts = terminusStorage(); + uint256 poolID = ts.currentPoolID + 1; + setPoolController(poolID, msg.sender); + ts.poolCapacity[poolID] = _capacity; + ts.currentPoolID++; + return poolID; + } + + function enforcePoolIsController(uint256 poolID, address maybeController) + internal + view + { + TerminusStorage storage ts = terminusStorage(); + require( + ts.poolController[poolID] == maybeController, + "LibTerminus: Must be pool controller" + ); + } + + function _isApprovedForPool(uint256 poolID, address operator) + internal + view + returns (bool) + { + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + if (operator == ts.poolController[poolID]) { + return true; + } else if (ts.globalPoolOperatorApprovals[poolID][operator]) { + return true; + } + return false; + } + + function _approveForPool(uint256 poolID, address operator) internal { + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.globalPoolOperatorApprovals[poolID][operator] = true; + } + + function _unapproveForPool(uint256 poolID, address operator) internal { + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.globalPoolOperatorApprovals[poolID][operator] = false; + } +} diff --git a/contracts/terminus/TerminusFacet.sol b/contracts/terminus/TerminusFacet.sol new file mode 100644 index 00000000..b0c49c5f --- /dev/null +++ b/contracts/terminus/TerminusFacet.sol @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: Apache-2.0 + +/** + * Authors: Moonstream Engineering (engineering@moonstream.to) + * GitHub: https://github.com/bugout-dev/dao + * + * This is an implementation of the Terminus decentralized authorization contract. + * + * Terminus users can create authorization pools. Each authorization pool has the following properties: + * 1. Controller: The address that controls the pool. Initially set to be the address of the pool creator. + * 2. Pool URI: Metadata URI for the authorization pool. + * 3. Pool capacity: The total number of tokens that can be minted in that authorization pool. + * 4. Pool supply: The number of tokens that have actually been minted in that authorization pool. + * 5. Transferable: A boolean value which denotes whether or not tokens from that pool can be transfered + * between addresses. (Note: Implemented by TerminusStorage.poolNotTransferable since we expect most + * pools to be transferable. This negation is better for storage + gas since false is default value + * in map to bool.) + * 6. Burnable: A boolean value which denotes whether or not tokens from that pool can be burned. + */ + +pragma solidity ^0.8.0; + +import "@openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; +import "./ERC1155WithTerminusStorage.sol"; +import "./LibTerminus.sol"; +import "../diamond/libraries/LibDiamond.sol"; + +contract TerminusFacet is ERC1155WithTerminusStorage { + constructor() { + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.controller = msg.sender; + } + + event PoolMintBatch( + uint256 indexed id, + address indexed operator, + address from, + address[] toAddresses, + uint256[] amounts + ); + + function setController(address newController) external { + LibTerminus.enforceIsController(); + LibTerminus.setController(newController); + } + + function poolMintBatch( + uint256 id, + address[] memory toAddresses, + uint256[] memory amounts + ) public { + require( + toAddresses.length == amounts.length, + "TerminusFacet: _poolMintBatch -- toAddresses and amounts length mismatch" + ); + address operator = _msgSender(); + require( + isApprovedForPool(id, operator), + "TerminusFacet: poolMintBatch -- caller is neither owner nor approved" + ); + + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + + uint256 i = 0; + uint256 totalAmount = 0; + + for (i = 0; i < toAddresses.length; i++) { + address to = toAddresses[i]; + uint256 amount = amounts[i]; + require( + to != address(0), + "TerminusFacet: _poolMintBatch -- cannot mint to zero address" + ); + totalAmount += amount; + ts.poolBalances[id][to] += amount; + emit TransferSingle(operator, address(0), to, id, amount); + } + + require( + ts.poolSupply[id] + totalAmount <= ts.poolCapacity[id], + "TerminusFacet: _poolMintBatch -- Minted tokens would exceed pool capacity" + ); + ts.poolSupply[id] += totalAmount; + + emit PoolMintBatch(id, operator, address(0), toAddresses, amounts); + } + + function terminusController() external view returns (address) { + return LibTerminus.terminusStorage().controller; + } + + function paymentToken() external view returns (address) { + return LibTerminus.terminusStorage().paymentToken; + } + + function setPaymentToken(address newPaymentToken) external { + LibTerminus.enforceIsController(); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.paymentToken = newPaymentToken; + } + + function poolBasePrice() external view returns (uint256) { + return LibTerminus.terminusStorage().poolBasePrice; + } + + function setPoolBasePrice(uint256 newBasePrice) external { + LibTerminus.enforceIsController(); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.poolBasePrice = newBasePrice; + } + + function _paymentTokenContract() internal view returns (IERC20) { + address paymentTokenAddress = LibTerminus + .terminusStorage() + .paymentToken; + require( + paymentTokenAddress != address(0), + "TerminusFacet: Payment token has not been set" + ); + return IERC20(paymentTokenAddress); + } + + function withdrawPayments(address toAddress, uint256 amount) external { + LibTerminus.enforceIsController(); + require( + _msgSender() == toAddress, + "TerminusFacet: withdrawPayments -- Controller can only withdraw to self" + ); + IERC20 paymentTokenContract = _paymentTokenContract(); + paymentTokenContract.transfer(toAddress, amount); + } + + function contractURI() public view returns (string memory) { + return LibTerminus.terminusStorage().contractURI; + } + + function setContractURI(string memory _contractURI) external { + LibTerminus.enforceIsController(); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.contractURI = _contractURI; + } + + function setURI(uint256 poolID, string memory poolURI) external { + LibTerminus.enforcePoolIsController(poolID, _msgSender()); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.poolURI[poolID] = poolURI; + } + + function totalPools() external view returns (uint256) { + return LibTerminus.terminusStorage().currentPoolID; + } + + function setPoolController(uint256 poolID, address newController) external { + LibTerminus.enforcePoolIsController(poolID, msg.sender); + LibTerminus.setPoolController(poolID, newController); + } + + function terminusPoolController(uint256 poolID) + external + view + returns (address) + { + return LibTerminus.terminusStorage().poolController[poolID]; + } + + function terminusPoolCapacity(uint256 poolID) + external + view + returns (uint256) + { + return LibTerminus.terminusStorage().poolCapacity[poolID]; + } + + function terminusPoolSupply(uint256 poolID) + external + view + returns (uint256) + { + return LibTerminus.terminusStorage().poolSupply[poolID]; + } + + function poolIsTransferable(uint256 poolID) external view returns (bool) { + return !LibTerminus.terminusStorage().poolNotTransferable[poolID]; + } + + function poolIsBurnable(uint256 poolID) external view returns (bool) { + return LibTerminus.terminusStorage().poolBurnable[poolID]; + } + + function setPoolTransferable(uint256 poolID, bool transferable) external { + LibTerminus.enforcePoolIsController(poolID, msg.sender); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.poolNotTransferable[poolID] = !transferable; + } + + function setPoolBurnable(uint256 poolID, bool burnable) external { + LibTerminus.enforcePoolIsController(poolID, msg.sender); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.poolBurnable[poolID] = burnable; + } + + function createSimplePool(uint256 _capacity) external returns (uint256) { + LibTerminus.enforceIsController(); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + uint256 requiredPayment = ts.poolBasePrice; + + if (requiredPayment > 0) { + IERC20 paymentTokenContract = _paymentTokenContract(); + require( + paymentTokenContract.allowance(_msgSender(), address(this)) >= + requiredPayment, + "TerminusFacet: createSimplePool -- Insufficient allowance on payment token" + ); + require( + paymentTokenContract.transferFrom( + msg.sender, + address(this), + requiredPayment + ), + "TerminusFacet: createSimplePool -- Transfer of payment token was unsuccessful" + ); + } + return LibTerminus.createSimplePool(_capacity); + } + + function createPoolV1( + uint256 _capacity, + bool _transferable, + bool _burnable + ) external returns (uint256) { + LibTerminus.enforceIsController(); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + uint256 requiredPayment = ts.poolBasePrice; + if (requiredPayment > 0) { + IERC20 paymentTokenContract = _paymentTokenContract(); + require( + paymentTokenContract.allowance(_msgSender(), address(this)) >= + requiredPayment, + "TerminusFacet: createPoolV1 -- Insufficient allowance on payment token" + ); + require( + paymentTokenContract.transferFrom( + msg.sender, + address(this), + requiredPayment + ), + "TerminusFacet: createPoolV1 -- Transfer of payment token was unsuccessful" + ); + } + uint256 poolID = LibTerminus.createSimplePool(_capacity); + if (!_transferable) { + ts.poolNotTransferable[poolID] = true; + } + if (_burnable) { + ts.poolBurnable[poolID] = true; + } + return poolID; + } + + function createPoolV2( + uint256 _capacity, + bool _transferable, + bool _burnable, + string memory poolURI + ) external returns (uint256) { + LibTerminus.enforceIsController(); + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + uint256 requiredPayment = ts.poolBasePrice; + if (requiredPayment > 0) { + IERC20 paymentTokenContract = _paymentTokenContract(); + require( + paymentTokenContract.allowance(_msgSender(), address(this)) >= + requiredPayment, + "TerminusFacet: createPoolV2 -- Insufficient allowance on payment token" + ); + require( + paymentTokenContract.transferFrom( + msg.sender, + address(this), + requiredPayment + ), + "TerminusFacet: createPoolV2 -- Transfer of payment token was unsuccessful" + ); + } + uint256 poolID = LibTerminus.createSimplePool(_capacity); + if (!_transferable) { + ts.poolNotTransferable[poolID] = true; + } + if (_burnable) { + ts.poolBurnable[poolID] = true; + } + ts.poolURI[poolID] = poolURI; + return poolID; + } + + function mint( + address to, + uint256 poolID, + uint256 amount, + bytes memory data + ) external { + require( + isApprovedForPool(poolID, msg.sender), + "TerminusFacet: mint -- caller is neither owner nor approved" + ); + _mint(to, poolID, amount, data); + } + + function mintBatch( + address to, + uint256[] memory poolIDs, + uint256[] memory amounts, + bytes memory data + ) external { + for (uint256 i = 0; i < poolIDs.length; i++) { + require( + isApprovedForPool(poolIDs[i], msg.sender), + "TerminusFacet: mintBatch -- caller is neither owner nor approved" + ); + } + _mintBatch(to, poolIDs, amounts, data); + } + + function burn( + address from, + uint256 poolID, + uint256 amount + ) external { + address operator = _msgSender(); + require( + operator == from || isApprovedForPool(poolID, operator), + "TerminusFacet: burn -- caller is neither owner nor approved" + ); + _burn(from, poolID, amount); + } +} diff --git a/contracts/terminus/TerminusInitializer.sol b/contracts/terminus/TerminusInitializer.sol new file mode 100644 index 00000000..c7066832 --- /dev/null +++ b/contracts/terminus/TerminusInitializer.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 + +/** + * Authors: Moonstream Engineering (engineering@moonstream.to) + * GitHub: https://github.com/bugout-dev/dao + * + * Initializer for Terminus contract. Used when mounting a new TerminusFacet onto its diamond proxy. + */ + +pragma solidity ^0.8.9; + +import "@openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol"; +import "@openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol"; +import "../diamond/libraries/LibDiamond.sol"; +import "./LibTerminus.sol"; + +contract TerminusInitializer { + function init() external { + LibDiamond.enforceIsContractOwner(); + LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage(); + ds.supportedInterfaces[type(IERC1155).interfaceId] = true; + ds.supportedInterfaces[type(IERC1155MetadataURI).interfaceId] = true; + + LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage(); + ts.controller = msg.sender; + } +} diff --git a/contracts/terminus/TerminusPermissions.sol b/contracts/terminus/TerminusPermissions.sol new file mode 100644 index 00000000..b58f0610 --- /dev/null +++ b/contracts/terminus/TerminusPermissions.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 + +/** + * Authors: Moonstream Engineering (engineering@moonstream.to) + * GitHub: https://github.com/bugout-dev/dao + * + */ + +import "@openzeppelin-contracts/contracts/access/Ownable.sol"; +import "./TerminusFacet.sol"; + +pragma solidity ^0.8.9; + +abstract contract TerminusPermissions { + function _holdsPoolToken( + address terminusAddress, + uint256 poolId, + uint256 _amount + ) internal view returns (bool) { + TerminusFacet terminus = TerminusFacet(terminusAddress); + return terminus.balanceOf(msg.sender, poolId) >= _amount; + } + + modifier holdsPoolToken(address terminusAddress, uint256 poolId) { + require( + _holdsPoolToken(terminusAddress, poolId, 1), + "TerminusPermissions.holdsPoolToken: Sender doens't hold pool tokens" + ); + _; + } + + modifier spendsPoolToken(address terminusAddress, uint256 poolId) { + require( + _holdsPoolToken(terminusAddress, poolId, 1), + "TerminusPermissions.spendsPoolToken: Sender doens't hold pool tokens" + ); + TerminusFacet terminusContract = TerminusFacet(terminusAddress); + terminusContract.burn(msg.sender, poolId, 1); + _; + } +} diff --git a/contracts/terminus/controller/LibTerminusController.sol b/contracts/terminus/controller/LibTerminusController.sol new file mode 100644 index 00000000..7ad1aec7 --- /dev/null +++ b/contracts/terminus/controller/LibTerminusController.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: Apache-2.0 + +/** + * Authors: Moonstream Engineering (engineering@moonstream.to) + * GitHub: https://github.com/bugout-dev/dao + * + */ + +pragma solidity ^0.8.9; + +struct TerminusPool { + address terminusAddress; + uint256 poolId; +} + +library LibTerminusController { + bytes32 constant TERMINUS_CONTROLLER_STORAGE_POSITION = + keccak256("moonstreamdao.eth.storage.terminus.controller"); + + struct TerminusControllerStorage { + address terminusAddress; + TerminusPool terminusMainAdminPool; + mapping(uint256 => TerminusPool) poolController; + } + + function terminusControllerStorage() + internal + pure + returns (TerminusControllerStorage storage es) + { + bytes32 position = TERMINUS_CONTROLLER_STORAGE_POSITION; + assembly { + es.slot := position + } + } +} diff --git a/contracts/terminus/controller/TerminusControllerFacet.sol b/contracts/terminus/controller/TerminusControllerFacet.sol new file mode 100644 index 00000000..06f1bea2 --- /dev/null +++ b/contracts/terminus/controller/TerminusControllerFacet.sol @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: Apache-2.0 + +/** + * Authors: Moonstream Engineering (engineering@moonstream.to) + * GitHub: https://github.com/bugout-dev/dao + * + * This contract stands as a proxy for the Terminus contract + * with a ability to whitelist operators by using Terminus Pools + */ +import "@openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; +import "../TerminusFacet.sol"; +import "../TerminusPermissions.sol"; +import "./LibTerminusController.sol"; +import "../../TokenDrainerFacet.sol"; + +pragma solidity ^0.8.9; + +// Permissions: +// - Contract owner can change _TERMINUS_MAIN_ADMIN_POOL_ID (+ all other operations?) +// - Holder of _TERMINUS_MAIN_ADMIN_POOL_ID can change poolControllerPoolID, create pool (+ pool operations?) +// - PoolController can: mint/burn + setURI + +contract TerminusControllerFacet is TerminusPermissions, TokenDrainerFacet { + /** + * @dev Checks if the caller holds the Admin Pool token or PoolController of pool with poolID + * @param poolId The poolID to check + */ + modifier onlyPoolController(uint256 poolId) { + TerminusPool memory pool = LibTerminusController + .terminusControllerStorage() + .poolController[poolId]; + + TerminusPool memory adminPool = LibTerminusController + .terminusControllerStorage() + .terminusMainAdminPool; + require( + _holdsPoolToken(adminPool.terminusAddress, adminPool.poolId, 1) || + _holdsPoolToken(pool.terminusAddress, pool.poolId, 1), + "TerminusControllerFacet.onlyPoolController: Sender doens't hold pool controller token" + ); + _; + } + + /** + * @dev Checks if the caller holds the Admin Pool token + */ + modifier onlyMainAdmin() { + TerminusPool memory adminPool = LibTerminusController + .terminusControllerStorage() + .terminusMainAdminPool; + require( + _holdsPoolToken(adminPool.terminusAddress, adminPool.poolId, 1), + "TerminusControllerFacet.onlyPoolController: Sender doens't hold pool controller token" + ); + _; + } + + function initTerminusController( + address terminusAddress, + address _TERMINUS_MAIN_ADMIN_POOL_TERMINUS_ADDRESS, + uint256 _TERMINUS_MAIN_ADMIN_POOL_ID + ) public { + LibTerminusController.TerminusControllerStorage + storage ts = LibTerminusController.terminusControllerStorage(); + + ts.terminusMainAdminPool = TerminusPool( + _TERMINUS_MAIN_ADMIN_POOL_TERMINUS_ADDRESS, + _TERMINUS_MAIN_ADMIN_POOL_ID + ); + ts.terminusAddress = terminusAddress; + } + + function terminusContract() internal view returns (TerminusFacet) { + return + TerminusFacet( + LibTerminusController + .terminusControllerStorage() + .terminusAddress + ); + } + + function getTerminusPoolControllerPool( + uint256 poolId + ) public view returns (TerminusPool memory) { + return + LibTerminusController.terminusControllerStorage().poolController[ + poolId + ]; + } + + function getTerminusAddress() public view returns (address) { + return + LibTerminusController.terminusControllerStorage().terminusAddress; + } + + function getTerminusMainAdminPoolId() + public + view + returns (TerminusPool memory) + { + return + LibTerminusController + .terminusControllerStorage() + .terminusMainAdminPool; + } + + /** + * @dev Gives permission to the holder of the (poolControllerPoolId,terminusAddress) + * to mint/burn/setURI for the pool with poolId + */ + function setPoolControlPermissions( + uint256 poolId, + address terminusAddress, + uint256 poolControllerPoolId + ) public onlyMainAdmin { + LibTerminusController.terminusControllerStorage().poolController[ + poolId + ] = TerminusPool(terminusAddress, poolControllerPoolId); + } + + // PROXY FUNCTIONS: + + /** + * @dev Sets the controller of the terminus contract + */ + function setController(address newController) external { + LibDiamond.enforceIsContractOwner(); + terminusContract().setController(newController); + } + + function poolMintBatch( + uint256 id, + address[] memory toAddresses, + uint256[] memory amounts + ) public onlyPoolController(id) { + terminusContract().poolMintBatch(id, toAddresses, amounts); + } + + function terminusController() external view returns (address) { + return terminusContract().terminusController(); + } + + function contractURI() public view returns (string memory) { + return terminusContract().contractURI(); + } + + function setContractURI(string memory _contractURI) external onlyMainAdmin { + terminusContract().setContractURI(_contractURI); + } + + function setURI( + uint256 poolID, + string memory poolURI + ) external onlyPoolController(poolID) { + terminusContract().setURI(poolID, poolURI); + } + + function totalPools() external view returns (uint256) { + return terminusContract().totalPools(); + } + + function setPoolController( + uint256 poolID, + address newController + ) external onlyMainAdmin { + terminusContract().setPoolController(poolID, newController); + } + + function terminusPoolController( + uint256 poolID + ) external view returns (address) { + return terminusContract().terminusPoolController(poolID); + } + + function terminusPoolCapacity( + uint256 poolID + ) external view returns (uint256) { + return terminusContract().terminusPoolCapacity(poolID); + } + + function terminusPoolSupply( + uint256 poolID + ) external view returns (uint256) { + return terminusContract().terminusPoolSupply(poolID); + } + + function isApprovedForPool( + uint256 poolID, + address operator + ) public view returns (bool) { + return terminusContract().isApprovedForPool(poolID, operator); + } + + function approveForPool( + uint256 poolID, + address operator + ) external onlyPoolController(poolID) { + terminusContract().approveForPool(poolID, operator); + } + + function unapproveForPool( + uint256 poolID, + address operator + ) external onlyPoolController(poolID) { + terminusContract().unapproveForPool(poolID, operator); + } + + function _approvePoolCreationPayments() internal { + IERC20 paymentToken = IERC20(terminusContract().paymentToken()); + uint256 fee = terminusContract().poolBasePrice(); + uint256 contractBalance = paymentToken.balanceOf(address(this)); + require( + contractBalance >= fee, + "TerminusControllerFacet._getPoolCreationPayments: Not enough funds, pls transfet payment tokens to terminusController contract" + ); + paymentToken.approve(getTerminusAddress(), fee); + } + + function createSimplePool( + uint256 _capacity + ) external onlyMainAdmin returns (uint256) { + _approvePoolCreationPayments(); + return terminusContract().createSimplePool(_capacity); + } + + function createPoolV1( + uint256 _capacity, + bool _transferable, + bool _burnable + ) external onlyMainAdmin returns (uint256) { + _approvePoolCreationPayments(); + return + terminusContract().createPoolV1( + _capacity, + _transferable, + _burnable + ); + } + + function mint( + address to, + uint256 poolID, + uint256 amount, + bytes memory data + ) external onlyPoolController(poolID) { + terminusContract().mint(to, poolID, amount, data); + } + + function mintBatch( + address to, + uint256[] memory poolIDs, + uint256[] memory amounts, + bytes memory data + ) external onlyMainAdmin { + terminusContract().mintBatch(to, poolIDs, amounts, data); + } + + function burn( + address from, + uint256 poolID, + uint256 amount + ) external onlyPoolController(poolID) { + terminusContract().burn(from, poolID, amount); + } + + function balanceOf( + address account, + uint256 id + ) public view returns (uint256) { + return terminusContract().balanceOf(account, id); + } +} From 49169dfa00f11ecb4b3b260914437080b0db3776 Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Sun, 20 Aug 2023 17:51:40 -0700 Subject: [PATCH 03/12] Updated MockTerminus to use local Terminus implementation --- contracts/mock/MockTerminus.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/mock/MockTerminus.sol b/contracts/mock/MockTerminus.sol index c014b205..eab907e1 100644 --- a/contracts/mock/MockTerminus.sol +++ b/contracts/mock/MockTerminus.sol @@ -2,7 +2,7 @@ ///@notice This contract is for mock for terminus token (used only for cli generation). pragma solidity ^0.8.0; -import "@moonstream/contracts/terminus/TerminusFacet.sol"; +import "../terminus/TerminusFacet.sol"; contract MockTerminus is TerminusFacet { constructor() {} From e8c64084e0277fce034a7140193ddd4b689810c4 Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Sun, 20 Aug 2023 18:05:31 -0700 Subject: [PATCH 04/12] Removed github.com/bugout-dev/dao brownie dependency --- brownie-config.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/brownie-config.yaml b/brownie-config.yaml index 835be82c..b30d8c21 100644 --- a/brownie-config.yaml +++ b/brownie-config.yaml @@ -1,6 +1,5 @@ dependencies: - "OpenZeppelin/openzeppelin-contracts@4.4.0" - - "bugout-dev/dao@0.0.7" - "smartcontractkit/chainlink@1.13.3" compiler: @@ -8,5 +7,4 @@ compiler: remappings: - "@openzeppelin-contracts=OpenZeppelin/openzeppelin-contracts@4.4.0" - "@openzeppelin/contracts=OpenZeppelin/openzeppelin-contracts@4.4.0" - - "@moonstream=bugout-dev/dao@0.0.7" - "@chainlink=smartcontractkit/chainlink@1.13.3" From 6cc9fd1a7c18ad0c0e94f43c5224d9cf41eedce9 Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Sun, 20 Aug 2023 18:09:02 -0700 Subject: [PATCH 05/12] Added Python codegen for Terminus-related contracts --- cli/web3cli/TerminusControllerFacet.py | 1114 +++++++++++++++++++++ cli/web3cli/TerminusFacet.py | 1250 ++++++++++++++++++++++++ cli/web3cli/TerminusInitializer.py | 225 +++++ cli/web3cli/TerminusPermissions.py | 207 ++++ 4 files changed, 2796 insertions(+) create mode 100644 cli/web3cli/TerminusControllerFacet.py create mode 100644 cli/web3cli/TerminusFacet.py create mode 100644 cli/web3cli/TerminusInitializer.py create mode 100644 cli/web3cli/TerminusPermissions.py diff --git a/cli/web3cli/TerminusControllerFacet.py b/cli/web3cli/TerminusControllerFacet.py new file mode 100644 index 00000000..601e9018 --- /dev/null +++ b/cli/web3cli/TerminusControllerFacet.py @@ -0,0 +1,1114 @@ +# Code generated by moonworm : https://github.com/moonstream-to/moonworm +# Moonworm version : 0.7.1 + +import argparse +import json +import os +from pathlib import Path +from typing import Any, Dict, List, Optional, Union + +from brownie import Contract, network, project +from brownie.network.contract import ContractContainer +from eth_typing.evm import ChecksumAddress + + +PROJECT_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +BUILD_DIRECTORY = os.path.join(PROJECT_DIRECTORY, "build", "contracts") + + +def boolean_argument_type(raw_value: str) -> bool: + TRUE_VALUES = ["1", "t", "y", "true", "yes"] + FALSE_VALUES = ["0", "f", "n", "false", "no"] + + if raw_value.lower() in TRUE_VALUES: + return True + elif raw_value.lower() in FALSE_VALUES: + return False + + raise ValueError( + f"Invalid boolean argument: {raw_value}. Value must be one of: {','.join(TRUE_VALUES + FALSE_VALUES)}" + ) + + +def bytes_argument_type(raw_value: str) -> str: + return raw_value + + +def get_abi_json(abi_name: str) -> List[Dict[str, Any]]: + abi_full_path = os.path.join(BUILD_DIRECTORY, f"{abi_name}.json") + if not os.path.isfile(abi_full_path): + raise IOError( + f"File does not exist: {abi_full_path}. Maybe you have to compile the smart contracts?" + ) + + with open(abi_full_path, "r") as ifp: + build = json.load(ifp) + + abi_json = build.get("abi") + if abi_json is None: + raise ValueError(f"Could not find ABI definition in: {abi_full_path}") + + return abi_json + + +def contract_from_build(abi_name: str) -> ContractContainer: + # This is workaround because brownie currently doesn't support loading the same project multiple + # times. This causes problems when using multiple contracts from the same project in the same + # python project. + PROJECT = project.main.Project("moonworm", Path(PROJECT_DIRECTORY)) + + abi_full_path = os.path.join(BUILD_DIRECTORY, f"{abi_name}.json") + if not os.path.isfile(abi_full_path): + raise IOError( + f"File does not exist: {abi_full_path}. Maybe you have to compile the smart contracts?" + ) + + with open(abi_full_path, "r") as ifp: + build = json.load(ifp) + + return ContractContainer(PROJECT, build) + + +class TerminusControllerFacet: + def __init__(self, contract_address: Optional[ChecksumAddress]): + self.contract_name = "TerminusControllerFacet" + self.address = contract_address + self.contract = None + self.abi = get_abi_json("TerminusControllerFacet") + if self.address is not None: + self.contract: Optional[Contract] = Contract.from_abi( + self.contract_name, self.address, self.abi + ) + + def deploy(self, transaction_config): + contract_class = contract_from_build(self.contract_name) + deployed_contract = contract_class.deploy(transaction_config) + self.address = deployed_contract.address + self.contract = deployed_contract + return deployed_contract.tx + + def assert_contract_is_instantiated(self) -> None: + if self.contract is None: + raise Exception("contract has not been instantiated") + + def verify_contract(self): + self.assert_contract_is_instantiated() + contract_class = contract_from_build(self.contract_name) + contract_class.publish_source(self.contract) + + def approve_for_pool( + self, pool_id: int, operator: ChecksumAddress, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.approveForPool(pool_id, operator, transaction_config) + + def balance_of( + self, + account: ChecksumAddress, + id: int, + block_number: Optional[Union[str, int]] = "latest", + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.balanceOf.call(account, id, block_identifier=block_number) + + def burn( + self, from_: ChecksumAddress, pool_id: int, amount: int, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.burn(from_, pool_id, amount, transaction_config) + + def contract_uri(self, block_number: Optional[Union[str, int]] = "latest") -> Any: + self.assert_contract_is_instantiated() + return self.contract.contractURI.call(block_identifier=block_number) + + def create_pool_v1( + self, _capacity: int, _transferable: bool, _burnable: bool, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.createPoolV1( + _capacity, _transferable, _burnable, transaction_config + ) + + def create_simple_pool(self, _capacity: int, transaction_config) -> Any: + self.assert_contract_is_instantiated() + return self.contract.createSimplePool(_capacity, transaction_config) + + def drain_erc1155( + self, + token_address: ChecksumAddress, + token_id: int, + receiver_address: ChecksumAddress, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.drainERC1155( + token_address, token_id, receiver_address, transaction_config + ) + + def drain_erc20( + self, + token_address: ChecksumAddress, + receiver_address: ChecksumAddress, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.drainERC20( + token_address, receiver_address, transaction_config + ) + + def get_terminus_address( + self, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.getTerminusAddress.call(block_identifier=block_number) + + def get_terminus_main_admin_pool_id( + self, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.getTerminusMainAdminPoolId.call( + block_identifier=block_number + ) + + def get_terminus_pool_controller_pool( + self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.getTerminusPoolControllerPool.call( + pool_id, block_identifier=block_number + ) + + def init_terminus_controller( + self, + terminus_address: ChecksumAddress, + _terminus_main_admin_pool_terminus_address: ChecksumAddress, + _terminus_main_admin_pool_id: int, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.initTerminusController( + terminus_address, + _terminus_main_admin_pool_terminus_address, + _terminus_main_admin_pool_id, + transaction_config, + ) + + def is_approved_for_pool( + self, + pool_id: int, + operator: ChecksumAddress, + block_number: Optional[Union[str, int]] = "latest", + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.isApprovedForPool.call( + pool_id, operator, block_identifier=block_number + ) + + def mint( + self, + to: ChecksumAddress, + pool_id: int, + amount: int, + data: bytes, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.mint(to, pool_id, amount, data, transaction_config) + + def mint_batch( + self, + to: ChecksumAddress, + pool_i_ds: List, + amounts: List, + data: bytes, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.mintBatch(to, pool_i_ds, amounts, data, transaction_config) + + def pool_mint_batch( + self, id: int, to_addresses: List, amounts: List, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.poolMintBatch( + id, to_addresses, amounts, transaction_config + ) + + def set_contract_uri(self, _contract_uri: str, transaction_config) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setContractURI(_contract_uri, transaction_config) + + def set_controller( + self, new_controller: ChecksumAddress, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setController(new_controller, transaction_config) + + def set_pool_control_permissions( + self, + pool_id: int, + terminus_address: ChecksumAddress, + pool_controller_pool_id: int, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setPoolControlPermissions( + pool_id, terminus_address, pool_controller_pool_id, transaction_config + ) + + def set_pool_controller( + self, pool_id: int, new_controller: ChecksumAddress, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setPoolController( + pool_id, new_controller, transaction_config + ) + + def set_uri(self, pool_id: int, pool_uri: str, transaction_config) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setURI(pool_id, pool_uri, transaction_config) + + def terminus_controller( + self, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.terminusController.call(block_identifier=block_number) + + def terminus_pool_capacity( + self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.terminusPoolCapacity.call( + pool_id, block_identifier=block_number + ) + + def terminus_pool_controller( + self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.terminusPoolController.call( + pool_id, block_identifier=block_number + ) + + def terminus_pool_supply( + self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.terminusPoolSupply.call( + pool_id, block_identifier=block_number + ) + + def total_pools(self, block_number: Optional[Union[str, int]] = "latest") -> Any: + self.assert_contract_is_instantiated() + return self.contract.totalPools.call(block_identifier=block_number) + + def unapprove_for_pool( + self, pool_id: int, operator: ChecksumAddress, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.unapproveForPool(pool_id, operator, transaction_config) + + def withdraw_erc1155( + self, + token_address: ChecksumAddress, + token_id: int, + amount: int, + receiver_address: ChecksumAddress, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.withdrawERC1155( + token_address, token_id, amount, receiver_address, transaction_config + ) + + def withdraw_erc20( + self, + token_address: ChecksumAddress, + amount: int, + receiver_address: ChecksumAddress, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.withdrawERC20( + token_address, amount, receiver_address, transaction_config + ) + + def withdraw_erc721( + self, + token_address: ChecksumAddress, + token_id: int, + receiver_address: ChecksumAddress, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.withdrawERC721( + token_address, token_id, receiver_address, transaction_config + ) + + +def get_transaction_config(args: argparse.Namespace) -> Dict[str, Any]: + signer = network.accounts.load(args.sender, args.password) + transaction_config: Dict[str, Any] = {"from": signer} + if args.gas_price is not None: + transaction_config["gas_price"] = args.gas_price + if args.max_fee_per_gas is not None: + transaction_config["max_fee"] = args.max_fee_per_gas + if args.max_priority_fee_per_gas is not None: + transaction_config["priority_fee"] = args.max_priority_fee_per_gas + if args.confirmations is not None: + transaction_config["required_confs"] = args.confirmations + if args.nonce is not None: + transaction_config["nonce"] = args.nonce + return transaction_config + + +def add_default_arguments(parser: argparse.ArgumentParser, transact: bool) -> None: + parser.add_argument( + "--network", required=True, help="Name of brownie network to connect to" + ) + parser.add_argument( + "--address", required=False, help="Address of deployed contract to connect to" + ) + if not transact: + parser.add_argument( + "--block-number", + required=False, + type=int, + help="Call at the given block number, defaults to latest", + ) + return + parser.add_argument( + "--sender", required=True, help="Path to keystore file for transaction sender" + ) + parser.add_argument( + "--password", + required=False, + help="Password to keystore file (if you do not provide it, you will be prompted for it)", + ) + parser.add_argument( + "--gas-price", default=None, help="Gas price at which to submit transaction" + ) + parser.add_argument( + "--max-fee-per-gas", + default=None, + help="Max fee per gas for EIP1559 transactions", + ) + parser.add_argument( + "--max-priority-fee-per-gas", + default=None, + help="Max priority fee per gas for EIP1559 transactions", + ) + parser.add_argument( + "--confirmations", + type=int, + default=None, + help="Number of confirmations to await before considering a transaction completed", + ) + parser.add_argument( + "--nonce", type=int, default=None, help="Nonce for the transaction (optional)" + ) + parser.add_argument( + "--value", default=None, help="Value of the transaction in wei(optional)" + ) + parser.add_argument("--verbose", action="store_true", help="Print verbose output") + + +def handle_deploy(args: argparse.Namespace) -> None: + network.connect(args.network) + transaction_config = get_transaction_config(args) + contract = TerminusControllerFacet(None) + result = contract.deploy(transaction_config=transaction_config) + print(result) + if args.verbose: + print(result.info()) + + +def handle_verify_contract(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + result = contract.verify_contract() + print(result) + + +def handle_approve_for_pool(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.approve_for_pool( + pool_id=args.pool_id, + operator=args.operator, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_balance_of(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + result = contract.balance_of( + account=args.account, id=args.id, block_number=args.block_number + ) + print(result) + + +def handle_burn(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.burn( + from_=args.from_arg, + pool_id=args.pool_id, + amount=args.amount, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_contract_uri(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + result = contract.contract_uri(block_number=args.block_number) + print(result) + + +def handle_create_pool_v1(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.create_pool_v1( + _capacity=args.capacity_arg, + _transferable=args.transferable_arg, + _burnable=args.burnable_arg, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_create_simple_pool(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.create_simple_pool( + _capacity=args.capacity_arg, transaction_config=transaction_config + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_drain_erc1155(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.drain_erc1155( + token_address=args.token_address, + token_id=args.token_id, + receiver_address=args.receiver_address, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_drain_erc20(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.drain_erc20( + token_address=args.token_address, + receiver_address=args.receiver_address, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_get_terminus_address(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + result = contract.get_terminus_address(block_number=args.block_number) + print(result) + + +def handle_get_terminus_main_admin_pool_id(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + result = contract.get_terminus_main_admin_pool_id(block_number=args.block_number) + print(result) + + +def handle_get_terminus_pool_controller_pool(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + result = contract.get_terminus_pool_controller_pool( + pool_id=args.pool_id, block_number=args.block_number + ) + print(result) + + +def handle_init_terminus_controller(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.init_terminus_controller( + terminus_address=args.terminus_address, + _terminus_main_admin_pool_terminus_address=args.terminus_main_admin_pool_terminus_address_arg, + _terminus_main_admin_pool_id=args.terminus_main_admin_pool_id_arg, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_is_approved_for_pool(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + result = contract.is_approved_for_pool( + pool_id=args.pool_id, operator=args.operator, block_number=args.block_number + ) + print(result) + + +def handle_mint(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.mint( + to=args.to, + pool_id=args.pool_id, + amount=args.amount, + data=args.data, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_mint_batch(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.mint_batch( + to=args.to, + pool_i_ds=args.pool_i_ds, + amounts=args.amounts, + data=args.data, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_pool_mint_batch(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.pool_mint_batch( + id=args.id, + to_addresses=args.to_addresses, + amounts=args.amounts, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_contract_uri(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_contract_uri( + _contract_uri=args.contract_uri_arg, transaction_config=transaction_config + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_controller(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_controller( + new_controller=args.new_controller, transaction_config=transaction_config + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_pool_control_permissions(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_pool_control_permissions( + pool_id=args.pool_id, + terminus_address=args.terminus_address, + pool_controller_pool_id=args.pool_controller_pool_id, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_pool_controller(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_pool_controller( + pool_id=args.pool_id, + new_controller=args.new_controller, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_uri(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_uri( + pool_id=args.pool_id, + pool_uri=args.pool_uri, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_terminus_controller(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + result = contract.terminus_controller(block_number=args.block_number) + print(result) + + +def handle_terminus_pool_capacity(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + result = contract.terminus_pool_capacity( + pool_id=args.pool_id, block_number=args.block_number + ) + print(result) + + +def handle_terminus_pool_controller(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + result = contract.terminus_pool_controller( + pool_id=args.pool_id, block_number=args.block_number + ) + print(result) + + +def handle_terminus_pool_supply(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + result = contract.terminus_pool_supply( + pool_id=args.pool_id, block_number=args.block_number + ) + print(result) + + +def handle_total_pools(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + result = contract.total_pools(block_number=args.block_number) + print(result) + + +def handle_unapprove_for_pool(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.unapprove_for_pool( + pool_id=args.pool_id, + operator=args.operator, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_withdraw_erc1155(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.withdraw_erc1155( + token_address=args.token_address, + token_id=args.token_id, + amount=args.amount, + receiver_address=args.receiver_address, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_withdraw_erc20(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.withdraw_erc20( + token_address=args.token_address, + amount=args.amount, + receiver_address=args.receiver_address, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_withdraw_erc721(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusControllerFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.withdraw_erc721( + token_address=args.token_address, + token_id=args.token_id, + receiver_address=args.receiver_address, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def generate_cli() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="CLI for TerminusControllerFacet") + parser.set_defaults(func=lambda _: parser.print_help()) + subcommands = parser.add_subparsers() + + deploy_parser = subcommands.add_parser("deploy") + add_default_arguments(deploy_parser, True) + deploy_parser.set_defaults(func=handle_deploy) + + verify_contract_parser = subcommands.add_parser("verify-contract") + add_default_arguments(verify_contract_parser, False) + verify_contract_parser.set_defaults(func=handle_verify_contract) + + approve_for_pool_parser = subcommands.add_parser("approve-for-pool") + add_default_arguments(approve_for_pool_parser, True) + approve_for_pool_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + approve_for_pool_parser.add_argument( + "--operator", required=True, help="Type: address" + ) + approve_for_pool_parser.set_defaults(func=handle_approve_for_pool) + + balance_of_parser = subcommands.add_parser("balance-of") + add_default_arguments(balance_of_parser, False) + balance_of_parser.add_argument("--account", required=True, help="Type: address") + balance_of_parser.add_argument( + "--id", required=True, help="Type: uint256", type=int + ) + balance_of_parser.set_defaults(func=handle_balance_of) + + burn_parser = subcommands.add_parser("burn") + add_default_arguments(burn_parser, True) + burn_parser.add_argument("--from-arg", required=True, help="Type: address") + burn_parser.add_argument("--pool-id", required=True, help="Type: uint256", type=int) + burn_parser.add_argument("--amount", required=True, help="Type: uint256", type=int) + burn_parser.set_defaults(func=handle_burn) + + contract_uri_parser = subcommands.add_parser("contract-uri") + add_default_arguments(contract_uri_parser, False) + contract_uri_parser.set_defaults(func=handle_contract_uri) + + create_pool_v1_parser = subcommands.add_parser("create-pool-v1") + add_default_arguments(create_pool_v1_parser, True) + create_pool_v1_parser.add_argument( + "--capacity-arg", required=True, help="Type: uint256", type=int + ) + create_pool_v1_parser.add_argument( + "--transferable-arg", + required=True, + help="Type: bool", + type=boolean_argument_type, + ) + create_pool_v1_parser.add_argument( + "--burnable-arg", required=True, help="Type: bool", type=boolean_argument_type + ) + create_pool_v1_parser.set_defaults(func=handle_create_pool_v1) + + create_simple_pool_parser = subcommands.add_parser("create-simple-pool") + add_default_arguments(create_simple_pool_parser, True) + create_simple_pool_parser.add_argument( + "--capacity-arg", required=True, help="Type: uint256", type=int + ) + create_simple_pool_parser.set_defaults(func=handle_create_simple_pool) + + drain_erc1155_parser = subcommands.add_parser("drain-erc1155") + add_default_arguments(drain_erc1155_parser, True) + drain_erc1155_parser.add_argument( + "--token-address", required=True, help="Type: address" + ) + drain_erc1155_parser.add_argument( + "--token-id", required=True, help="Type: uint256", type=int + ) + drain_erc1155_parser.add_argument( + "--receiver-address", required=True, help="Type: address" + ) + drain_erc1155_parser.set_defaults(func=handle_drain_erc1155) + + drain_erc20_parser = subcommands.add_parser("drain-erc20") + add_default_arguments(drain_erc20_parser, True) + drain_erc20_parser.add_argument( + "--token-address", required=True, help="Type: address" + ) + drain_erc20_parser.add_argument( + "--receiver-address", required=True, help="Type: address" + ) + drain_erc20_parser.set_defaults(func=handle_drain_erc20) + + get_terminus_address_parser = subcommands.add_parser("get-terminus-address") + add_default_arguments(get_terminus_address_parser, False) + get_terminus_address_parser.set_defaults(func=handle_get_terminus_address) + + get_terminus_main_admin_pool_id_parser = subcommands.add_parser( + "get-terminus-main-admin-pool-id" + ) + add_default_arguments(get_terminus_main_admin_pool_id_parser, False) + get_terminus_main_admin_pool_id_parser.set_defaults( + func=handle_get_terminus_main_admin_pool_id + ) + + get_terminus_pool_controller_pool_parser = subcommands.add_parser( + "get-terminus-pool-controller-pool" + ) + add_default_arguments(get_terminus_pool_controller_pool_parser, False) + get_terminus_pool_controller_pool_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + get_terminus_pool_controller_pool_parser.set_defaults( + func=handle_get_terminus_pool_controller_pool + ) + + init_terminus_controller_parser = subcommands.add_parser("init-terminus-controller") + add_default_arguments(init_terminus_controller_parser, True) + init_terminus_controller_parser.add_argument( + "--terminus-address", required=True, help="Type: address" + ) + init_terminus_controller_parser.add_argument( + "--terminus-main-admin-pool-terminus-address-arg", + required=True, + help="Type: address", + ) + init_terminus_controller_parser.add_argument( + "--terminus-main-admin-pool-id-arg", + required=True, + help="Type: uint256", + type=int, + ) + init_terminus_controller_parser.set_defaults(func=handle_init_terminus_controller) + + is_approved_for_pool_parser = subcommands.add_parser("is-approved-for-pool") + add_default_arguments(is_approved_for_pool_parser, False) + is_approved_for_pool_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + is_approved_for_pool_parser.add_argument( + "--operator", required=True, help="Type: address" + ) + is_approved_for_pool_parser.set_defaults(func=handle_is_approved_for_pool) + + mint_parser = subcommands.add_parser("mint") + add_default_arguments(mint_parser, True) + mint_parser.add_argument("--to", required=True, help="Type: address") + mint_parser.add_argument("--pool-id", required=True, help="Type: uint256", type=int) + mint_parser.add_argument("--amount", required=True, help="Type: uint256", type=int) + mint_parser.add_argument( + "--data", required=True, help="Type: bytes", type=bytes_argument_type + ) + mint_parser.set_defaults(func=handle_mint) + + mint_batch_parser = subcommands.add_parser("mint-batch") + add_default_arguments(mint_batch_parser, True) + mint_batch_parser.add_argument("--to", required=True, help="Type: address") + mint_batch_parser.add_argument( + "--pool-i-ds", required=True, help="Type: uint256[]", nargs="+" + ) + mint_batch_parser.add_argument( + "--amounts", required=True, help="Type: uint256[]", nargs="+" + ) + mint_batch_parser.add_argument( + "--data", required=True, help="Type: bytes", type=bytes_argument_type + ) + mint_batch_parser.set_defaults(func=handle_mint_batch) + + pool_mint_batch_parser = subcommands.add_parser("pool-mint-batch") + add_default_arguments(pool_mint_batch_parser, True) + pool_mint_batch_parser.add_argument( + "--id", required=True, help="Type: uint256", type=int + ) + pool_mint_batch_parser.add_argument( + "--to-addresses", required=True, help="Type: address[]", nargs="+" + ) + pool_mint_batch_parser.add_argument( + "--amounts", required=True, help="Type: uint256[]", nargs="+" + ) + pool_mint_batch_parser.set_defaults(func=handle_pool_mint_batch) + + set_contract_uri_parser = subcommands.add_parser("set-contract-uri") + add_default_arguments(set_contract_uri_parser, True) + set_contract_uri_parser.add_argument( + "--contract-uri-arg", required=True, help="Type: string", type=str + ) + set_contract_uri_parser.set_defaults(func=handle_set_contract_uri) + + set_controller_parser = subcommands.add_parser("set-controller") + add_default_arguments(set_controller_parser, True) + set_controller_parser.add_argument( + "--new-controller", required=True, help="Type: address" + ) + set_controller_parser.set_defaults(func=handle_set_controller) + + set_pool_control_permissions_parser = subcommands.add_parser( + "set-pool-control-permissions" + ) + add_default_arguments(set_pool_control_permissions_parser, True) + set_pool_control_permissions_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + set_pool_control_permissions_parser.add_argument( + "--terminus-address", required=True, help="Type: address" + ) + set_pool_control_permissions_parser.add_argument( + "--pool-controller-pool-id", required=True, help="Type: uint256", type=int + ) + set_pool_control_permissions_parser.set_defaults( + func=handle_set_pool_control_permissions + ) + + set_pool_controller_parser = subcommands.add_parser("set-pool-controller") + add_default_arguments(set_pool_controller_parser, True) + set_pool_controller_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + set_pool_controller_parser.add_argument( + "--new-controller", required=True, help="Type: address" + ) + set_pool_controller_parser.set_defaults(func=handle_set_pool_controller) + + set_uri_parser = subcommands.add_parser("set-uri") + add_default_arguments(set_uri_parser, True) + set_uri_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + set_uri_parser.add_argument( + "--pool-uri", required=True, help="Type: string", type=str + ) + set_uri_parser.set_defaults(func=handle_set_uri) + + terminus_controller_parser = subcommands.add_parser("terminus-controller") + add_default_arguments(terminus_controller_parser, False) + terminus_controller_parser.set_defaults(func=handle_terminus_controller) + + terminus_pool_capacity_parser = subcommands.add_parser("terminus-pool-capacity") + add_default_arguments(terminus_pool_capacity_parser, False) + terminus_pool_capacity_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + terminus_pool_capacity_parser.set_defaults(func=handle_terminus_pool_capacity) + + terminus_pool_controller_parser = subcommands.add_parser("terminus-pool-controller") + add_default_arguments(terminus_pool_controller_parser, False) + terminus_pool_controller_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + terminus_pool_controller_parser.set_defaults(func=handle_terminus_pool_controller) + + terminus_pool_supply_parser = subcommands.add_parser("terminus-pool-supply") + add_default_arguments(terminus_pool_supply_parser, False) + terminus_pool_supply_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + terminus_pool_supply_parser.set_defaults(func=handle_terminus_pool_supply) + + total_pools_parser = subcommands.add_parser("total-pools") + add_default_arguments(total_pools_parser, False) + total_pools_parser.set_defaults(func=handle_total_pools) + + unapprove_for_pool_parser = subcommands.add_parser("unapprove-for-pool") + add_default_arguments(unapprove_for_pool_parser, True) + unapprove_for_pool_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + unapprove_for_pool_parser.add_argument( + "--operator", required=True, help="Type: address" + ) + unapprove_for_pool_parser.set_defaults(func=handle_unapprove_for_pool) + + withdraw_erc1155_parser = subcommands.add_parser("withdraw-erc1155") + add_default_arguments(withdraw_erc1155_parser, True) + withdraw_erc1155_parser.add_argument( + "--token-address", required=True, help="Type: address" + ) + withdraw_erc1155_parser.add_argument( + "--token-id", required=True, help="Type: uint256", type=int + ) + withdraw_erc1155_parser.add_argument( + "--amount", required=True, help="Type: uint256", type=int + ) + withdraw_erc1155_parser.add_argument( + "--receiver-address", required=True, help="Type: address" + ) + withdraw_erc1155_parser.set_defaults(func=handle_withdraw_erc1155) + + withdraw_erc20_parser = subcommands.add_parser("withdraw-erc20") + add_default_arguments(withdraw_erc20_parser, True) + withdraw_erc20_parser.add_argument( + "--token-address", required=True, help="Type: address" + ) + withdraw_erc20_parser.add_argument( + "--amount", required=True, help="Type: uint256", type=int + ) + withdraw_erc20_parser.add_argument( + "--receiver-address", required=True, help="Type: address" + ) + withdraw_erc20_parser.set_defaults(func=handle_withdraw_erc20) + + withdraw_erc721_parser = subcommands.add_parser("withdraw-erc721") + add_default_arguments(withdraw_erc721_parser, True) + withdraw_erc721_parser.add_argument( + "--token-address", required=True, help="Type: address" + ) + withdraw_erc721_parser.add_argument( + "--token-id", required=True, help="Type: uint256", type=int + ) + withdraw_erc721_parser.add_argument( + "--receiver-address", required=True, help="Type: address" + ) + withdraw_erc721_parser.set_defaults(func=handle_withdraw_erc721) + + return parser + + +def main() -> None: + parser = generate_cli() + args = parser.parse_args() + args.func(args) + + +if __name__ == "__main__": + main() diff --git a/cli/web3cli/TerminusFacet.py b/cli/web3cli/TerminusFacet.py new file mode 100644 index 00000000..f1d4b96e --- /dev/null +++ b/cli/web3cli/TerminusFacet.py @@ -0,0 +1,1250 @@ +# Code generated by moonworm : https://github.com/moonstream-to/moonworm +# Moonworm version : 0.7.1 + +import argparse +import json +import os +from pathlib import Path +from typing import Any, Dict, List, Optional, Union + +from brownie import Contract, network, project +from brownie.network.contract import ContractContainer +from eth_typing.evm import ChecksumAddress + + +PROJECT_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +BUILD_DIRECTORY = os.path.join(PROJECT_DIRECTORY, "build", "contracts") + + +def boolean_argument_type(raw_value: str) -> bool: + TRUE_VALUES = ["1", "t", "y", "true", "yes"] + FALSE_VALUES = ["0", "f", "n", "false", "no"] + + if raw_value.lower() in TRUE_VALUES: + return True + elif raw_value.lower() in FALSE_VALUES: + return False + + raise ValueError( + f"Invalid boolean argument: {raw_value}. Value must be one of: {','.join(TRUE_VALUES + FALSE_VALUES)}" + ) + + +def bytes_argument_type(raw_value: str) -> str: + return raw_value + + +def get_abi_json(abi_name: str) -> List[Dict[str, Any]]: + abi_full_path = os.path.join(BUILD_DIRECTORY, f"{abi_name}.json") + if not os.path.isfile(abi_full_path): + raise IOError( + f"File does not exist: {abi_full_path}. Maybe you have to compile the smart contracts?" + ) + + with open(abi_full_path, "r") as ifp: + build = json.load(ifp) + + abi_json = build.get("abi") + if abi_json is None: + raise ValueError(f"Could not find ABI definition in: {abi_full_path}") + + return abi_json + + +def contract_from_build(abi_name: str) -> ContractContainer: + # This is workaround because brownie currently doesn't support loading the same project multiple + # times. This causes problems when using multiple contracts from the same project in the same + # python project. + PROJECT = project.main.Project("moonworm", Path(PROJECT_DIRECTORY)) + + abi_full_path = os.path.join(BUILD_DIRECTORY, f"{abi_name}.json") + if not os.path.isfile(abi_full_path): + raise IOError( + f"File does not exist: {abi_full_path}. Maybe you have to compile the smart contracts?" + ) + + with open(abi_full_path, "r") as ifp: + build = json.load(ifp) + + return ContractContainer(PROJECT, build) + + +class TerminusFacet: + def __init__(self, contract_address: Optional[ChecksumAddress]): + self.contract_name = "TerminusFacet" + self.address = contract_address + self.contract = None + self.abi = get_abi_json("TerminusFacet") + if self.address is not None: + self.contract: Optional[Contract] = Contract.from_abi( + self.contract_name, self.address, self.abi + ) + + def deploy(self, transaction_config): + contract_class = contract_from_build(self.contract_name) + deployed_contract = contract_class.deploy(transaction_config) + self.address = deployed_contract.address + self.contract = deployed_contract + return deployed_contract.tx + + def assert_contract_is_instantiated(self) -> None: + if self.contract is None: + raise Exception("contract has not been instantiated") + + def verify_contract(self): + self.assert_contract_is_instantiated() + contract_class = contract_from_build(self.contract_name) + contract_class.publish_source(self.contract) + + def approve_for_pool( + self, pool_id: int, operator: ChecksumAddress, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.approveForPool(pool_id, operator, transaction_config) + + def balance_of( + self, + account: ChecksumAddress, + id: int, + block_number: Optional[Union[str, int]] = "latest", + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.balanceOf.call(account, id, block_identifier=block_number) + + def balance_of_batch( + self, + accounts: List, + ids: List, + block_number: Optional[Union[str, int]] = "latest", + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.balanceOfBatch.call( + accounts, ids, block_identifier=block_number + ) + + def burn( + self, from_: ChecksumAddress, pool_id: int, amount: int, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.burn(from_, pool_id, amount, transaction_config) + + def contract_uri(self, block_number: Optional[Union[str, int]] = "latest") -> Any: + self.assert_contract_is_instantiated() + return self.contract.contractURI.call(block_identifier=block_number) + + def create_pool_v1( + self, _capacity: int, _transferable: bool, _burnable: bool, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.createPoolV1( + _capacity, _transferable, _burnable, transaction_config + ) + + def create_pool_v2( + self, + _capacity: int, + _transferable: bool, + _burnable: bool, + pool_uri: str, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.createPoolV2( + _capacity, _transferable, _burnable, pool_uri, transaction_config + ) + + def create_simple_pool(self, _capacity: int, transaction_config) -> Any: + self.assert_contract_is_instantiated() + return self.contract.createSimplePool(_capacity, transaction_config) + + def is_approved_for_all( + self, + account: ChecksumAddress, + operator: ChecksumAddress, + block_number: Optional[Union[str, int]] = "latest", + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.isApprovedForAll.call( + account, operator, block_identifier=block_number + ) + + def is_approved_for_pool( + self, + pool_id: int, + operator: ChecksumAddress, + block_number: Optional[Union[str, int]] = "latest", + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.isApprovedForPool.call( + pool_id, operator, block_identifier=block_number + ) + + def mint( + self, + to: ChecksumAddress, + pool_id: int, + amount: int, + data: bytes, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.mint(to, pool_id, amount, data, transaction_config) + + def mint_batch( + self, + to: ChecksumAddress, + pool_i_ds: List, + amounts: List, + data: bytes, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.mintBatch(to, pool_i_ds, amounts, data, transaction_config) + + def payment_token(self, block_number: Optional[Union[str, int]] = "latest") -> Any: + self.assert_contract_is_instantiated() + return self.contract.paymentToken.call(block_identifier=block_number) + + def pool_base_price( + self, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.poolBasePrice.call(block_identifier=block_number) + + def pool_is_burnable( + self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.poolIsBurnable.call(pool_id, block_identifier=block_number) + + def pool_is_transferable( + self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.poolIsTransferable.call( + pool_id, block_identifier=block_number + ) + + def pool_mint_batch( + self, id: int, to_addresses: List, amounts: List, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.poolMintBatch( + id, to_addresses, amounts, transaction_config + ) + + def safe_batch_transfer_from( + self, + from_: ChecksumAddress, + to: ChecksumAddress, + ids: List, + amounts: List, + data: bytes, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.safeBatchTransferFrom( + from_, to, ids, amounts, data, transaction_config + ) + + def safe_transfer_from( + self, + from_: ChecksumAddress, + to: ChecksumAddress, + id: int, + amount: int, + data: bytes, + transaction_config, + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.safeTransferFrom( + from_, to, id, amount, data, transaction_config + ) + + def set_approval_for_all( + self, operator: ChecksumAddress, approved: bool, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setApprovalForAll(operator, approved, transaction_config) + + def set_contract_uri(self, _contract_uri: str, transaction_config) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setContractURI(_contract_uri, transaction_config) + + def set_controller( + self, new_controller: ChecksumAddress, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setController(new_controller, transaction_config) + + def set_payment_token( + self, new_payment_token: ChecksumAddress, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setPaymentToken(new_payment_token, transaction_config) + + def set_pool_base_price(self, new_base_price: int, transaction_config) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setPoolBasePrice(new_base_price, transaction_config) + + def set_pool_burnable( + self, pool_id: int, burnable: bool, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setPoolBurnable(pool_id, burnable, transaction_config) + + def set_pool_controller( + self, pool_id: int, new_controller: ChecksumAddress, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setPoolController( + pool_id, new_controller, transaction_config + ) + + def set_pool_transferable( + self, pool_id: int, transferable: bool, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setPoolTransferable( + pool_id, transferable, transaction_config + ) + + def set_uri(self, pool_id: int, pool_uri: str, transaction_config) -> Any: + self.assert_contract_is_instantiated() + return self.contract.setURI(pool_id, pool_uri, transaction_config) + + def supports_interface( + self, interface_id: bytes, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.supportsInterface.call( + interface_id, block_identifier=block_number + ) + + def terminus_controller( + self, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.terminusController.call(block_identifier=block_number) + + def terminus_pool_capacity( + self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.terminusPoolCapacity.call( + pool_id, block_identifier=block_number + ) + + def terminus_pool_controller( + self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.terminusPoolController.call( + pool_id, block_identifier=block_number + ) + + def terminus_pool_supply( + self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.terminusPoolSupply.call( + pool_id, block_identifier=block_number + ) + + def total_pools(self, block_number: Optional[Union[str, int]] = "latest") -> Any: + self.assert_contract_is_instantiated() + return self.contract.totalPools.call(block_identifier=block_number) + + def unapprove_for_pool( + self, pool_id: int, operator: ChecksumAddress, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.unapproveForPool(pool_id, operator, transaction_config) + + def uri( + self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.uri.call(pool_id, block_identifier=block_number) + + def withdraw_payments( + self, to_address: ChecksumAddress, amount: int, transaction_config + ) -> Any: + self.assert_contract_is_instantiated() + return self.contract.withdrawPayments(to_address, amount, transaction_config) + + +def get_transaction_config(args: argparse.Namespace) -> Dict[str, Any]: + signer = network.accounts.load(args.sender, args.password) + transaction_config: Dict[str, Any] = {"from": signer} + if args.gas_price is not None: + transaction_config["gas_price"] = args.gas_price + if args.max_fee_per_gas is not None: + transaction_config["max_fee"] = args.max_fee_per_gas + if args.max_priority_fee_per_gas is not None: + transaction_config["priority_fee"] = args.max_priority_fee_per_gas + if args.confirmations is not None: + transaction_config["required_confs"] = args.confirmations + if args.nonce is not None: + transaction_config["nonce"] = args.nonce + return transaction_config + + +def add_default_arguments(parser: argparse.ArgumentParser, transact: bool) -> None: + parser.add_argument( + "--network", required=True, help="Name of brownie network to connect to" + ) + parser.add_argument( + "--address", required=False, help="Address of deployed contract to connect to" + ) + if not transact: + parser.add_argument( + "--block-number", + required=False, + type=int, + help="Call at the given block number, defaults to latest", + ) + return + parser.add_argument( + "--sender", required=True, help="Path to keystore file for transaction sender" + ) + parser.add_argument( + "--password", + required=False, + help="Password to keystore file (if you do not provide it, you will be prompted for it)", + ) + parser.add_argument( + "--gas-price", default=None, help="Gas price at which to submit transaction" + ) + parser.add_argument( + "--max-fee-per-gas", + default=None, + help="Max fee per gas for EIP1559 transactions", + ) + parser.add_argument( + "--max-priority-fee-per-gas", + default=None, + help="Max priority fee per gas for EIP1559 transactions", + ) + parser.add_argument( + "--confirmations", + type=int, + default=None, + help="Number of confirmations to await before considering a transaction completed", + ) + parser.add_argument( + "--nonce", type=int, default=None, help="Nonce for the transaction (optional)" + ) + parser.add_argument( + "--value", default=None, help="Value of the transaction in wei(optional)" + ) + parser.add_argument("--verbose", action="store_true", help="Print verbose output") + + +def handle_deploy(args: argparse.Namespace) -> None: + network.connect(args.network) + transaction_config = get_transaction_config(args) + contract = TerminusFacet(None) + result = contract.deploy(transaction_config=transaction_config) + print(result) + if args.verbose: + print(result.info()) + + +def handle_verify_contract(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.verify_contract() + print(result) + + +def handle_approve_for_pool(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.approve_for_pool( + pool_id=args.pool_id, + operator=args.operator, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_balance_of(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.balance_of( + account=args.account, id=args.id, block_number=args.block_number + ) + print(result) + + +def handle_balance_of_batch(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.balance_of_batch( + accounts=args.accounts, ids=args.ids, block_number=args.block_number + ) + print(result) + + +def handle_burn(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.burn( + from_=args.from_arg, + pool_id=args.pool_id, + amount=args.amount, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_contract_uri(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.contract_uri(block_number=args.block_number) + print(result) + + +def handle_create_pool_v1(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.create_pool_v1( + _capacity=args.capacity_arg, + _transferable=args.transferable_arg, + _burnable=args.burnable_arg, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_create_pool_v2(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.create_pool_v2( + _capacity=args.capacity_arg, + _transferable=args.transferable_arg, + _burnable=args.burnable_arg, + pool_uri=args.pool_uri, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_create_simple_pool(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.create_simple_pool( + _capacity=args.capacity_arg, transaction_config=transaction_config + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_is_approved_for_all(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.is_approved_for_all( + account=args.account, operator=args.operator, block_number=args.block_number + ) + print(result) + + +def handle_is_approved_for_pool(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.is_approved_for_pool( + pool_id=args.pool_id, operator=args.operator, block_number=args.block_number + ) + print(result) + + +def handle_mint(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.mint( + to=args.to, + pool_id=args.pool_id, + amount=args.amount, + data=args.data, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_mint_batch(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.mint_batch( + to=args.to, + pool_i_ds=args.pool_i_ds, + amounts=args.amounts, + data=args.data, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_payment_token(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.payment_token(block_number=args.block_number) + print(result) + + +def handle_pool_base_price(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.pool_base_price(block_number=args.block_number) + print(result) + + +def handle_pool_is_burnable(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.pool_is_burnable( + pool_id=args.pool_id, block_number=args.block_number + ) + print(result) + + +def handle_pool_is_transferable(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.pool_is_transferable( + pool_id=args.pool_id, block_number=args.block_number + ) + print(result) + + +def handle_pool_mint_batch(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.pool_mint_batch( + id=args.id, + to_addresses=args.to_addresses, + amounts=args.amounts, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_safe_batch_transfer_from(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.safe_batch_transfer_from( + from_=args.from_arg, + to=args.to, + ids=args.ids, + amounts=args.amounts, + data=args.data, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_safe_transfer_from(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.safe_transfer_from( + from_=args.from_arg, + to=args.to, + id=args.id, + amount=args.amount, + data=args.data, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_approval_for_all(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_approval_for_all( + operator=args.operator, + approved=args.approved, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_contract_uri(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_contract_uri( + _contract_uri=args.contract_uri_arg, transaction_config=transaction_config + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_controller(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_controller( + new_controller=args.new_controller, transaction_config=transaction_config + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_payment_token(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_payment_token( + new_payment_token=args.new_payment_token, transaction_config=transaction_config + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_pool_base_price(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_pool_base_price( + new_base_price=args.new_base_price, transaction_config=transaction_config + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_pool_burnable(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_pool_burnable( + pool_id=args.pool_id, + burnable=args.burnable, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_pool_controller(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_pool_controller( + pool_id=args.pool_id, + new_controller=args.new_controller, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_pool_transferable(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_pool_transferable( + pool_id=args.pool_id, + transferable=args.transferable, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_set_uri(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.set_uri( + pool_id=args.pool_id, + pool_uri=args.pool_uri, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_supports_interface(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.supports_interface( + interface_id=args.interface_id, block_number=args.block_number + ) + print(result) + + +def handle_terminus_controller(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.terminus_controller(block_number=args.block_number) + print(result) + + +def handle_terminus_pool_capacity(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.terminus_pool_capacity( + pool_id=args.pool_id, block_number=args.block_number + ) + print(result) + + +def handle_terminus_pool_controller(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.terminus_pool_controller( + pool_id=args.pool_id, block_number=args.block_number + ) + print(result) + + +def handle_terminus_pool_supply(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.terminus_pool_supply( + pool_id=args.pool_id, block_number=args.block_number + ) + print(result) + + +def handle_total_pools(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.total_pools(block_number=args.block_number) + print(result) + + +def handle_unapprove_for_pool(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.unapprove_for_pool( + pool_id=args.pool_id, + operator=args.operator, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def handle_uri(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + result = contract.uri(pool_id=args.pool_id, block_number=args.block_number) + print(result) + + +def handle_withdraw_payments(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusFacet(args.address) + transaction_config = get_transaction_config(args) + result = contract.withdraw_payments( + to_address=args.to_address, + amount=args.amount, + transaction_config=transaction_config, + ) + print(result) + if args.verbose: + print(result.info()) + + +def generate_cli() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="CLI for TerminusFacet") + parser.set_defaults(func=lambda _: parser.print_help()) + subcommands = parser.add_subparsers() + + deploy_parser = subcommands.add_parser("deploy") + add_default_arguments(deploy_parser, True) + deploy_parser.set_defaults(func=handle_deploy) + + verify_contract_parser = subcommands.add_parser("verify-contract") + add_default_arguments(verify_contract_parser, False) + verify_contract_parser.set_defaults(func=handle_verify_contract) + + approve_for_pool_parser = subcommands.add_parser("approve-for-pool") + add_default_arguments(approve_for_pool_parser, True) + approve_for_pool_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + approve_for_pool_parser.add_argument( + "--operator", required=True, help="Type: address" + ) + approve_for_pool_parser.set_defaults(func=handle_approve_for_pool) + + balance_of_parser = subcommands.add_parser("balance-of") + add_default_arguments(balance_of_parser, False) + balance_of_parser.add_argument("--account", required=True, help="Type: address") + balance_of_parser.add_argument( + "--id", required=True, help="Type: uint256", type=int + ) + balance_of_parser.set_defaults(func=handle_balance_of) + + balance_of_batch_parser = subcommands.add_parser("balance-of-batch") + add_default_arguments(balance_of_batch_parser, False) + balance_of_batch_parser.add_argument( + "--accounts", required=True, help="Type: address[]", nargs="+" + ) + balance_of_batch_parser.add_argument( + "--ids", required=True, help="Type: uint256[]", nargs="+" + ) + balance_of_batch_parser.set_defaults(func=handle_balance_of_batch) + + burn_parser = subcommands.add_parser("burn") + add_default_arguments(burn_parser, True) + burn_parser.add_argument("--from-arg", required=True, help="Type: address") + burn_parser.add_argument("--pool-id", required=True, help="Type: uint256", type=int) + burn_parser.add_argument("--amount", required=True, help="Type: uint256", type=int) + burn_parser.set_defaults(func=handle_burn) + + contract_uri_parser = subcommands.add_parser("contract-uri") + add_default_arguments(contract_uri_parser, False) + contract_uri_parser.set_defaults(func=handle_contract_uri) + + create_pool_v1_parser = subcommands.add_parser("create-pool-v1") + add_default_arguments(create_pool_v1_parser, True) + create_pool_v1_parser.add_argument( + "--capacity-arg", required=True, help="Type: uint256", type=int + ) + create_pool_v1_parser.add_argument( + "--transferable-arg", + required=True, + help="Type: bool", + type=boolean_argument_type, + ) + create_pool_v1_parser.add_argument( + "--burnable-arg", required=True, help="Type: bool", type=boolean_argument_type + ) + create_pool_v1_parser.set_defaults(func=handle_create_pool_v1) + + create_pool_v2_parser = subcommands.add_parser("create-pool-v2") + add_default_arguments(create_pool_v2_parser, True) + create_pool_v2_parser.add_argument( + "--capacity-arg", required=True, help="Type: uint256", type=int + ) + create_pool_v2_parser.add_argument( + "--transferable-arg", + required=True, + help="Type: bool", + type=boolean_argument_type, + ) + create_pool_v2_parser.add_argument( + "--burnable-arg", required=True, help="Type: bool", type=boolean_argument_type + ) + create_pool_v2_parser.add_argument( + "--pool-uri", required=True, help="Type: string", type=str + ) + create_pool_v2_parser.set_defaults(func=handle_create_pool_v2) + + create_simple_pool_parser = subcommands.add_parser("create-simple-pool") + add_default_arguments(create_simple_pool_parser, True) + create_simple_pool_parser.add_argument( + "--capacity-arg", required=True, help="Type: uint256", type=int + ) + create_simple_pool_parser.set_defaults(func=handle_create_simple_pool) + + is_approved_for_all_parser = subcommands.add_parser("is-approved-for-all") + add_default_arguments(is_approved_for_all_parser, False) + is_approved_for_all_parser.add_argument( + "--account", required=True, help="Type: address" + ) + is_approved_for_all_parser.add_argument( + "--operator", required=True, help="Type: address" + ) + is_approved_for_all_parser.set_defaults(func=handle_is_approved_for_all) + + is_approved_for_pool_parser = subcommands.add_parser("is-approved-for-pool") + add_default_arguments(is_approved_for_pool_parser, False) + is_approved_for_pool_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + is_approved_for_pool_parser.add_argument( + "--operator", required=True, help="Type: address" + ) + is_approved_for_pool_parser.set_defaults(func=handle_is_approved_for_pool) + + mint_parser = subcommands.add_parser("mint") + add_default_arguments(mint_parser, True) + mint_parser.add_argument("--to", required=True, help="Type: address") + mint_parser.add_argument("--pool-id", required=True, help="Type: uint256", type=int) + mint_parser.add_argument("--amount", required=True, help="Type: uint256", type=int) + mint_parser.add_argument( + "--data", required=True, help="Type: bytes", type=bytes_argument_type + ) + mint_parser.set_defaults(func=handle_mint) + + mint_batch_parser = subcommands.add_parser("mint-batch") + add_default_arguments(mint_batch_parser, True) + mint_batch_parser.add_argument("--to", required=True, help="Type: address") + mint_batch_parser.add_argument( + "--pool-i-ds", required=True, help="Type: uint256[]", nargs="+" + ) + mint_batch_parser.add_argument( + "--amounts", required=True, help="Type: uint256[]", nargs="+" + ) + mint_batch_parser.add_argument( + "--data", required=True, help="Type: bytes", type=bytes_argument_type + ) + mint_batch_parser.set_defaults(func=handle_mint_batch) + + payment_token_parser = subcommands.add_parser("payment-token") + add_default_arguments(payment_token_parser, False) + payment_token_parser.set_defaults(func=handle_payment_token) + + pool_base_price_parser = subcommands.add_parser("pool-base-price") + add_default_arguments(pool_base_price_parser, False) + pool_base_price_parser.set_defaults(func=handle_pool_base_price) + + pool_is_burnable_parser = subcommands.add_parser("pool-is-burnable") + add_default_arguments(pool_is_burnable_parser, False) + pool_is_burnable_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + pool_is_burnable_parser.set_defaults(func=handle_pool_is_burnable) + + pool_is_transferable_parser = subcommands.add_parser("pool-is-transferable") + add_default_arguments(pool_is_transferable_parser, False) + pool_is_transferable_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + pool_is_transferable_parser.set_defaults(func=handle_pool_is_transferable) + + pool_mint_batch_parser = subcommands.add_parser("pool-mint-batch") + add_default_arguments(pool_mint_batch_parser, True) + pool_mint_batch_parser.add_argument( + "--id", required=True, help="Type: uint256", type=int + ) + pool_mint_batch_parser.add_argument( + "--to-addresses", required=True, help="Type: address[]", nargs="+" + ) + pool_mint_batch_parser.add_argument( + "--amounts", required=True, help="Type: uint256[]", nargs="+" + ) + pool_mint_batch_parser.set_defaults(func=handle_pool_mint_batch) + + safe_batch_transfer_from_parser = subcommands.add_parser("safe-batch-transfer-from") + add_default_arguments(safe_batch_transfer_from_parser, True) + safe_batch_transfer_from_parser.add_argument( + "--from-arg", required=True, help="Type: address" + ) + safe_batch_transfer_from_parser.add_argument( + "--to", required=True, help="Type: address" + ) + safe_batch_transfer_from_parser.add_argument( + "--ids", required=True, help="Type: uint256[]", nargs="+" + ) + safe_batch_transfer_from_parser.add_argument( + "--amounts", required=True, help="Type: uint256[]", nargs="+" + ) + safe_batch_transfer_from_parser.add_argument( + "--data", required=True, help="Type: bytes", type=bytes_argument_type + ) + safe_batch_transfer_from_parser.set_defaults(func=handle_safe_batch_transfer_from) + + safe_transfer_from_parser = subcommands.add_parser("safe-transfer-from") + add_default_arguments(safe_transfer_from_parser, True) + safe_transfer_from_parser.add_argument( + "--from-arg", required=True, help="Type: address" + ) + safe_transfer_from_parser.add_argument("--to", required=True, help="Type: address") + safe_transfer_from_parser.add_argument( + "--id", required=True, help="Type: uint256", type=int + ) + safe_transfer_from_parser.add_argument( + "--amount", required=True, help="Type: uint256", type=int + ) + safe_transfer_from_parser.add_argument( + "--data", required=True, help="Type: bytes", type=bytes_argument_type + ) + safe_transfer_from_parser.set_defaults(func=handle_safe_transfer_from) + + set_approval_for_all_parser = subcommands.add_parser("set-approval-for-all") + add_default_arguments(set_approval_for_all_parser, True) + set_approval_for_all_parser.add_argument( + "--operator", required=True, help="Type: address" + ) + set_approval_for_all_parser.add_argument( + "--approved", required=True, help="Type: bool", type=boolean_argument_type + ) + set_approval_for_all_parser.set_defaults(func=handle_set_approval_for_all) + + set_contract_uri_parser = subcommands.add_parser("set-contract-uri") + add_default_arguments(set_contract_uri_parser, True) + set_contract_uri_parser.add_argument( + "--contract-uri-arg", required=True, help="Type: string", type=str + ) + set_contract_uri_parser.set_defaults(func=handle_set_contract_uri) + + set_controller_parser = subcommands.add_parser("set-controller") + add_default_arguments(set_controller_parser, True) + set_controller_parser.add_argument( + "--new-controller", required=True, help="Type: address" + ) + set_controller_parser.set_defaults(func=handle_set_controller) + + set_payment_token_parser = subcommands.add_parser("set-payment-token") + add_default_arguments(set_payment_token_parser, True) + set_payment_token_parser.add_argument( + "--new-payment-token", required=True, help="Type: address" + ) + set_payment_token_parser.set_defaults(func=handle_set_payment_token) + + set_pool_base_price_parser = subcommands.add_parser("set-pool-base-price") + add_default_arguments(set_pool_base_price_parser, True) + set_pool_base_price_parser.add_argument( + "--new-base-price", required=True, help="Type: uint256", type=int + ) + set_pool_base_price_parser.set_defaults(func=handle_set_pool_base_price) + + set_pool_burnable_parser = subcommands.add_parser("set-pool-burnable") + add_default_arguments(set_pool_burnable_parser, True) + set_pool_burnable_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + set_pool_burnable_parser.add_argument( + "--burnable", required=True, help="Type: bool", type=boolean_argument_type + ) + set_pool_burnable_parser.set_defaults(func=handle_set_pool_burnable) + + set_pool_controller_parser = subcommands.add_parser("set-pool-controller") + add_default_arguments(set_pool_controller_parser, True) + set_pool_controller_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + set_pool_controller_parser.add_argument( + "--new-controller", required=True, help="Type: address" + ) + set_pool_controller_parser.set_defaults(func=handle_set_pool_controller) + + set_pool_transferable_parser = subcommands.add_parser("set-pool-transferable") + add_default_arguments(set_pool_transferable_parser, True) + set_pool_transferable_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + set_pool_transferable_parser.add_argument( + "--transferable", required=True, help="Type: bool", type=boolean_argument_type + ) + set_pool_transferable_parser.set_defaults(func=handle_set_pool_transferable) + + set_uri_parser = subcommands.add_parser("set-uri") + add_default_arguments(set_uri_parser, True) + set_uri_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + set_uri_parser.add_argument( + "--pool-uri", required=True, help="Type: string", type=str + ) + set_uri_parser.set_defaults(func=handle_set_uri) + + supports_interface_parser = subcommands.add_parser("supports-interface") + add_default_arguments(supports_interface_parser, False) + supports_interface_parser.add_argument( + "--interface-id", required=True, help="Type: bytes4", type=bytes_argument_type + ) + supports_interface_parser.set_defaults(func=handle_supports_interface) + + terminus_controller_parser = subcommands.add_parser("terminus-controller") + add_default_arguments(terminus_controller_parser, False) + terminus_controller_parser.set_defaults(func=handle_terminus_controller) + + terminus_pool_capacity_parser = subcommands.add_parser("terminus-pool-capacity") + add_default_arguments(terminus_pool_capacity_parser, False) + terminus_pool_capacity_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + terminus_pool_capacity_parser.set_defaults(func=handle_terminus_pool_capacity) + + terminus_pool_controller_parser = subcommands.add_parser("terminus-pool-controller") + add_default_arguments(terminus_pool_controller_parser, False) + terminus_pool_controller_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + terminus_pool_controller_parser.set_defaults(func=handle_terminus_pool_controller) + + terminus_pool_supply_parser = subcommands.add_parser("terminus-pool-supply") + add_default_arguments(terminus_pool_supply_parser, False) + terminus_pool_supply_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + terminus_pool_supply_parser.set_defaults(func=handle_terminus_pool_supply) + + total_pools_parser = subcommands.add_parser("total-pools") + add_default_arguments(total_pools_parser, False) + total_pools_parser.set_defaults(func=handle_total_pools) + + unapprove_for_pool_parser = subcommands.add_parser("unapprove-for-pool") + add_default_arguments(unapprove_for_pool_parser, True) + unapprove_for_pool_parser.add_argument( + "--pool-id", required=True, help="Type: uint256", type=int + ) + unapprove_for_pool_parser.add_argument( + "--operator", required=True, help="Type: address" + ) + unapprove_for_pool_parser.set_defaults(func=handle_unapprove_for_pool) + + uri_parser = subcommands.add_parser("uri") + add_default_arguments(uri_parser, False) + uri_parser.add_argument("--pool-id", required=True, help="Type: uint256", type=int) + uri_parser.set_defaults(func=handle_uri) + + withdraw_payments_parser = subcommands.add_parser("withdraw-payments") + add_default_arguments(withdraw_payments_parser, True) + withdraw_payments_parser.add_argument( + "--to-address", required=True, help="Type: address" + ) + withdraw_payments_parser.add_argument( + "--amount", required=True, help="Type: uint256", type=int + ) + withdraw_payments_parser.set_defaults(func=handle_withdraw_payments) + + return parser + + +def main() -> None: + parser = generate_cli() + args = parser.parse_args() + args.func(args) + + +if __name__ == "__main__": + main() diff --git a/cli/web3cli/TerminusInitializer.py b/cli/web3cli/TerminusInitializer.py new file mode 100644 index 00000000..635e3be8 --- /dev/null +++ b/cli/web3cli/TerminusInitializer.py @@ -0,0 +1,225 @@ +# Code generated by moonworm : https://github.com/moonstream-to/moonworm +# Moonworm version : 0.7.1 + +import argparse +import json +import os +from pathlib import Path +from typing import Any, Dict, List, Optional, Union + +from brownie import Contract, network, project +from brownie.network.contract import ContractContainer +from eth_typing.evm import ChecksumAddress + + +PROJECT_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +BUILD_DIRECTORY = os.path.join(PROJECT_DIRECTORY, "build", "contracts") + + +def boolean_argument_type(raw_value: str) -> bool: + TRUE_VALUES = ["1", "t", "y", "true", "yes"] + FALSE_VALUES = ["0", "f", "n", "false", "no"] + + if raw_value.lower() in TRUE_VALUES: + return True + elif raw_value.lower() in FALSE_VALUES: + return False + + raise ValueError( + f"Invalid boolean argument: {raw_value}. Value must be one of: {','.join(TRUE_VALUES + FALSE_VALUES)}" + ) + + +def bytes_argument_type(raw_value: str) -> str: + return raw_value + + +def get_abi_json(abi_name: str) -> List[Dict[str, Any]]: + abi_full_path = os.path.join(BUILD_DIRECTORY, f"{abi_name}.json") + if not os.path.isfile(abi_full_path): + raise IOError( + f"File does not exist: {abi_full_path}. Maybe you have to compile the smart contracts?" + ) + + with open(abi_full_path, "r") as ifp: + build = json.load(ifp) + + abi_json = build.get("abi") + if abi_json is None: + raise ValueError(f"Could not find ABI definition in: {abi_full_path}") + + return abi_json + + +def contract_from_build(abi_name: str) -> ContractContainer: + # This is workaround because brownie currently doesn't support loading the same project multiple + # times. This causes problems when using multiple contracts from the same project in the same + # python project. + PROJECT = project.main.Project("moonworm", Path(PROJECT_DIRECTORY)) + + abi_full_path = os.path.join(BUILD_DIRECTORY, f"{abi_name}.json") + if not os.path.isfile(abi_full_path): + raise IOError( + f"File does not exist: {abi_full_path}. Maybe you have to compile the smart contracts?" + ) + + with open(abi_full_path, "r") as ifp: + build = json.load(ifp) + + return ContractContainer(PROJECT, build) + + +class TerminusInitializer: + def __init__(self, contract_address: Optional[ChecksumAddress]): + self.contract_name = "TerminusInitializer" + self.address = contract_address + self.contract = None + self.abi = get_abi_json("TerminusInitializer") + if self.address is not None: + self.contract: Optional[Contract] = Contract.from_abi( + self.contract_name, self.address, self.abi + ) + + def deploy(self, transaction_config): + contract_class = contract_from_build(self.contract_name) + deployed_contract = contract_class.deploy(transaction_config) + self.address = deployed_contract.address + self.contract = deployed_contract + return deployed_contract.tx + + def assert_contract_is_instantiated(self) -> None: + if self.contract is None: + raise Exception("contract has not been instantiated") + + def verify_contract(self): + self.assert_contract_is_instantiated() + contract_class = contract_from_build(self.contract_name) + contract_class.publish_source(self.contract) + + def init(self, transaction_config) -> Any: + self.assert_contract_is_instantiated() + return self.contract.init(transaction_config) + + +def get_transaction_config(args: argparse.Namespace) -> Dict[str, Any]: + signer = network.accounts.load(args.sender, args.password) + transaction_config: Dict[str, Any] = {"from": signer} + if args.gas_price is not None: + transaction_config["gas_price"] = args.gas_price + if args.max_fee_per_gas is not None: + transaction_config["max_fee"] = args.max_fee_per_gas + if args.max_priority_fee_per_gas is not None: + transaction_config["priority_fee"] = args.max_priority_fee_per_gas + if args.confirmations is not None: + transaction_config["required_confs"] = args.confirmations + if args.nonce is not None: + transaction_config["nonce"] = args.nonce + return transaction_config + + +def add_default_arguments(parser: argparse.ArgumentParser, transact: bool) -> None: + parser.add_argument( + "--network", required=True, help="Name of brownie network to connect to" + ) + parser.add_argument( + "--address", required=False, help="Address of deployed contract to connect to" + ) + if not transact: + parser.add_argument( + "--block-number", + required=False, + type=int, + help="Call at the given block number, defaults to latest", + ) + return + parser.add_argument( + "--sender", required=True, help="Path to keystore file for transaction sender" + ) + parser.add_argument( + "--password", + required=False, + help="Password to keystore file (if you do not provide it, you will be prompted for it)", + ) + parser.add_argument( + "--gas-price", default=None, help="Gas price at which to submit transaction" + ) + parser.add_argument( + "--max-fee-per-gas", + default=None, + help="Max fee per gas for EIP1559 transactions", + ) + parser.add_argument( + "--max-priority-fee-per-gas", + default=None, + help="Max priority fee per gas for EIP1559 transactions", + ) + parser.add_argument( + "--confirmations", + type=int, + default=None, + help="Number of confirmations to await before considering a transaction completed", + ) + parser.add_argument( + "--nonce", type=int, default=None, help="Nonce for the transaction (optional)" + ) + parser.add_argument( + "--value", default=None, help="Value of the transaction in wei(optional)" + ) + parser.add_argument("--verbose", action="store_true", help="Print verbose output") + + +def handle_deploy(args: argparse.Namespace) -> None: + network.connect(args.network) + transaction_config = get_transaction_config(args) + contract = TerminusInitializer(None) + result = contract.deploy(transaction_config=transaction_config) + print(result) + if args.verbose: + print(result.info()) + + +def handle_verify_contract(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusInitializer(args.address) + result = contract.verify_contract() + print(result) + + +def handle_init(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusInitializer(args.address) + transaction_config = get_transaction_config(args) + result = contract.init(transaction_config=transaction_config) + print(result) + if args.verbose: + print(result.info()) + + +def generate_cli() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="CLI for TerminusInitializer") + parser.set_defaults(func=lambda _: parser.print_help()) + subcommands = parser.add_subparsers() + + deploy_parser = subcommands.add_parser("deploy") + add_default_arguments(deploy_parser, True) + deploy_parser.set_defaults(func=handle_deploy) + + verify_contract_parser = subcommands.add_parser("verify-contract") + add_default_arguments(verify_contract_parser, False) + verify_contract_parser.set_defaults(func=handle_verify_contract) + + init_parser = subcommands.add_parser("init") + add_default_arguments(init_parser, True) + init_parser.set_defaults(func=handle_init) + + return parser + + +def main() -> None: + parser = generate_cli() + args = parser.parse_args() + args.func(args) + + +if __name__ == "__main__": + main() diff --git a/cli/web3cli/TerminusPermissions.py b/cli/web3cli/TerminusPermissions.py new file mode 100644 index 00000000..8ae25524 --- /dev/null +++ b/cli/web3cli/TerminusPermissions.py @@ -0,0 +1,207 @@ +# Code generated by moonworm : https://github.com/moonstream-to/moonworm +# Moonworm version : 0.7.1 + +import argparse +import json +import os +from pathlib import Path +from typing import Any, Dict, List, Optional, Union + +from brownie import Contract, network, project +from brownie.network.contract import ContractContainer +from eth_typing.evm import ChecksumAddress + + +PROJECT_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +BUILD_DIRECTORY = os.path.join(PROJECT_DIRECTORY, "build", "contracts") + + +def boolean_argument_type(raw_value: str) -> bool: + TRUE_VALUES = ["1", "t", "y", "true", "yes"] + FALSE_VALUES = ["0", "f", "n", "false", "no"] + + if raw_value.lower() in TRUE_VALUES: + return True + elif raw_value.lower() in FALSE_VALUES: + return False + + raise ValueError( + f"Invalid boolean argument: {raw_value}. Value must be one of: {','.join(TRUE_VALUES + FALSE_VALUES)}" + ) + + +def bytes_argument_type(raw_value: str) -> str: + return raw_value + + +def get_abi_json(abi_name: str) -> List[Dict[str, Any]]: + abi_full_path = os.path.join(BUILD_DIRECTORY, f"{abi_name}.json") + if not os.path.isfile(abi_full_path): + raise IOError( + f"File does not exist: {abi_full_path}. Maybe you have to compile the smart contracts?" + ) + + with open(abi_full_path, "r") as ifp: + build = json.load(ifp) + + abi_json = build.get("abi") + if abi_json is None: + raise ValueError(f"Could not find ABI definition in: {abi_full_path}") + + return abi_json + + +def contract_from_build(abi_name: str) -> ContractContainer: + # This is workaround because brownie currently doesn't support loading the same project multiple + # times. This causes problems when using multiple contracts from the same project in the same + # python project. + PROJECT = project.main.Project("moonworm", Path(PROJECT_DIRECTORY)) + + abi_full_path = os.path.join(BUILD_DIRECTORY, f"{abi_name}.json") + if not os.path.isfile(abi_full_path): + raise IOError( + f"File does not exist: {abi_full_path}. Maybe you have to compile the smart contracts?" + ) + + with open(abi_full_path, "r") as ifp: + build = json.load(ifp) + + return ContractContainer(PROJECT, build) + + +class TerminusPermissions: + def __init__(self, contract_address: Optional[ChecksumAddress]): + self.contract_name = "TerminusPermissions" + self.address = contract_address + self.contract = None + self.abi = get_abi_json("TerminusPermissions") + if self.address is not None: + self.contract: Optional[Contract] = Contract.from_abi( + self.contract_name, self.address, self.abi + ) + + def deploy(self, transaction_config): + contract_class = contract_from_build(self.contract_name) + deployed_contract = contract_class.deploy(transaction_config) + self.address = deployed_contract.address + self.contract = deployed_contract + return deployed_contract.tx + + def assert_contract_is_instantiated(self) -> None: + if self.contract is None: + raise Exception("contract has not been instantiated") + + def verify_contract(self): + self.assert_contract_is_instantiated() + contract_class = contract_from_build(self.contract_name) + contract_class.publish_source(self.contract) + + +def get_transaction_config(args: argparse.Namespace) -> Dict[str, Any]: + signer = network.accounts.load(args.sender, args.password) + transaction_config: Dict[str, Any] = {"from": signer} + if args.gas_price is not None: + transaction_config["gas_price"] = args.gas_price + if args.max_fee_per_gas is not None: + transaction_config["max_fee"] = args.max_fee_per_gas + if args.max_priority_fee_per_gas is not None: + transaction_config["priority_fee"] = args.max_priority_fee_per_gas + if args.confirmations is not None: + transaction_config["required_confs"] = args.confirmations + if args.nonce is not None: + transaction_config["nonce"] = args.nonce + return transaction_config + + +def add_default_arguments(parser: argparse.ArgumentParser, transact: bool) -> None: + parser.add_argument( + "--network", required=True, help="Name of brownie network to connect to" + ) + parser.add_argument( + "--address", required=False, help="Address of deployed contract to connect to" + ) + if not transact: + parser.add_argument( + "--block-number", + required=False, + type=int, + help="Call at the given block number, defaults to latest", + ) + return + parser.add_argument( + "--sender", required=True, help="Path to keystore file for transaction sender" + ) + parser.add_argument( + "--password", + required=False, + help="Password to keystore file (if you do not provide it, you will be prompted for it)", + ) + parser.add_argument( + "--gas-price", default=None, help="Gas price at which to submit transaction" + ) + parser.add_argument( + "--max-fee-per-gas", + default=None, + help="Max fee per gas for EIP1559 transactions", + ) + parser.add_argument( + "--max-priority-fee-per-gas", + default=None, + help="Max priority fee per gas for EIP1559 transactions", + ) + parser.add_argument( + "--confirmations", + type=int, + default=None, + help="Number of confirmations to await before considering a transaction completed", + ) + parser.add_argument( + "--nonce", type=int, default=None, help="Nonce for the transaction (optional)" + ) + parser.add_argument( + "--value", default=None, help="Value of the transaction in wei(optional)" + ) + parser.add_argument("--verbose", action="store_true", help="Print verbose output") + + +def handle_deploy(args: argparse.Namespace) -> None: + network.connect(args.network) + transaction_config = get_transaction_config(args) + contract = TerminusPermissions(None) + result = contract.deploy(transaction_config=transaction_config) + print(result) + if args.verbose: + print(result.info()) + + +def handle_verify_contract(args: argparse.Namespace) -> None: + network.connect(args.network) + contract = TerminusPermissions(args.address) + result = contract.verify_contract() + print(result) + + +def generate_cli() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="CLI for TerminusPermissions") + parser.set_defaults(func=lambda _: parser.print_help()) + subcommands = parser.add_subparsers() + + deploy_parser = subcommands.add_parser("deploy") + add_default_arguments(deploy_parser, True) + deploy_parser.set_defaults(func=handle_deploy) + + verify_contract_parser = subcommands.add_parser("verify-contract") + add_default_arguments(verify_contract_parser, False) + verify_contract_parser.set_defaults(func=handle_verify_contract) + + return parser + + +def main() -> None: + parser = generate_cli() + args = parser.parse_args() + args.func(args) + + +if __name__ == "__main__": + main() From f5ee0e38c5e4eb235a2497e9ddd82885e0c6a687 Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Sun, 20 Aug 2023 18:10:27 -0700 Subject: [PATCH 06/12] `web3cli terminus` now uses the TerminusFacet.py implementation Which means that deployment, contract verification, etc. all work now. --- cli/web3cli/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/web3cli/cli.py b/cli/web3cli/cli.py index 3684a50f..20ab1292 100644 --- a/cli/web3cli/cli.py +++ b/cli/web3cli/cli.py @@ -12,12 +12,12 @@ Lootbox, MockErc20, MockERC721, - ITerminus, setup_drop, CraftingFacet, GOFPFacet, GOFPPredicates, InventoryFacet, + TerminusFacet, ) @@ -56,7 +56,7 @@ def main() -> None: drop_parser = drop.generate_cli() subparsers.add_parser("drop", parents=[drop_parser], add_help=False) - terminus_parser = ITerminus.generate_cli() + terminus_parser = TerminusFacet.generate_cli() subparsers.add_parser("terminus", parents=[terminus_parser], add_help=False) crafting_parser = CraftingFacet.generate_cli() From 33dee9cbe6cb617b91becd998ce57361d83e13f9 Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Sun, 20 Aug 2023 18:27:04 -0700 Subject: [PATCH 07/12] Added `terminus-gogogo` Removed all `TerminusController` related functionality (see PR for more details): https://github.com/moonstream-to/web3/pull/334 --- cli/web3cli/TerminusControllerFacet.py | 1114 ----------------- cli/web3cli/core.py | 144 +++ .../controller/LibTerminusController.sol | 36 - .../controller/TerminusControllerFacet.sol | 272 ---- 4 files changed, 144 insertions(+), 1422 deletions(-) delete mode 100644 cli/web3cli/TerminusControllerFacet.py delete mode 100644 contracts/terminus/controller/LibTerminusController.sol delete mode 100644 contracts/terminus/controller/TerminusControllerFacet.sol diff --git a/cli/web3cli/TerminusControllerFacet.py b/cli/web3cli/TerminusControllerFacet.py deleted file mode 100644 index 601e9018..00000000 --- a/cli/web3cli/TerminusControllerFacet.py +++ /dev/null @@ -1,1114 +0,0 @@ -# Code generated by moonworm : https://github.com/moonstream-to/moonworm -# Moonworm version : 0.7.1 - -import argparse -import json -import os -from pathlib import Path -from typing import Any, Dict, List, Optional, Union - -from brownie import Contract, network, project -from brownie.network.contract import ContractContainer -from eth_typing.evm import ChecksumAddress - - -PROJECT_DIRECTORY = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) -BUILD_DIRECTORY = os.path.join(PROJECT_DIRECTORY, "build", "contracts") - - -def boolean_argument_type(raw_value: str) -> bool: - TRUE_VALUES = ["1", "t", "y", "true", "yes"] - FALSE_VALUES = ["0", "f", "n", "false", "no"] - - if raw_value.lower() in TRUE_VALUES: - return True - elif raw_value.lower() in FALSE_VALUES: - return False - - raise ValueError( - f"Invalid boolean argument: {raw_value}. Value must be one of: {','.join(TRUE_VALUES + FALSE_VALUES)}" - ) - - -def bytes_argument_type(raw_value: str) -> str: - return raw_value - - -def get_abi_json(abi_name: str) -> List[Dict[str, Any]]: - abi_full_path = os.path.join(BUILD_DIRECTORY, f"{abi_name}.json") - if not os.path.isfile(abi_full_path): - raise IOError( - f"File does not exist: {abi_full_path}. Maybe you have to compile the smart contracts?" - ) - - with open(abi_full_path, "r") as ifp: - build = json.load(ifp) - - abi_json = build.get("abi") - if abi_json is None: - raise ValueError(f"Could not find ABI definition in: {abi_full_path}") - - return abi_json - - -def contract_from_build(abi_name: str) -> ContractContainer: - # This is workaround because brownie currently doesn't support loading the same project multiple - # times. This causes problems when using multiple contracts from the same project in the same - # python project. - PROJECT = project.main.Project("moonworm", Path(PROJECT_DIRECTORY)) - - abi_full_path = os.path.join(BUILD_DIRECTORY, f"{abi_name}.json") - if not os.path.isfile(abi_full_path): - raise IOError( - f"File does not exist: {abi_full_path}. Maybe you have to compile the smart contracts?" - ) - - with open(abi_full_path, "r") as ifp: - build = json.load(ifp) - - return ContractContainer(PROJECT, build) - - -class TerminusControllerFacet: - def __init__(self, contract_address: Optional[ChecksumAddress]): - self.contract_name = "TerminusControllerFacet" - self.address = contract_address - self.contract = None - self.abi = get_abi_json("TerminusControllerFacet") - if self.address is not None: - self.contract: Optional[Contract] = Contract.from_abi( - self.contract_name, self.address, self.abi - ) - - def deploy(self, transaction_config): - contract_class = contract_from_build(self.contract_name) - deployed_contract = contract_class.deploy(transaction_config) - self.address = deployed_contract.address - self.contract = deployed_contract - return deployed_contract.tx - - def assert_contract_is_instantiated(self) -> None: - if self.contract is None: - raise Exception("contract has not been instantiated") - - def verify_contract(self): - self.assert_contract_is_instantiated() - contract_class = contract_from_build(self.contract_name) - contract_class.publish_source(self.contract) - - def approve_for_pool( - self, pool_id: int, operator: ChecksumAddress, transaction_config - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.approveForPool(pool_id, operator, transaction_config) - - def balance_of( - self, - account: ChecksumAddress, - id: int, - block_number: Optional[Union[str, int]] = "latest", - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.balanceOf.call(account, id, block_identifier=block_number) - - def burn( - self, from_: ChecksumAddress, pool_id: int, amount: int, transaction_config - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.burn(from_, pool_id, amount, transaction_config) - - def contract_uri(self, block_number: Optional[Union[str, int]] = "latest") -> Any: - self.assert_contract_is_instantiated() - return self.contract.contractURI.call(block_identifier=block_number) - - def create_pool_v1( - self, _capacity: int, _transferable: bool, _burnable: bool, transaction_config - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.createPoolV1( - _capacity, _transferable, _burnable, transaction_config - ) - - def create_simple_pool(self, _capacity: int, transaction_config) -> Any: - self.assert_contract_is_instantiated() - return self.contract.createSimplePool(_capacity, transaction_config) - - def drain_erc1155( - self, - token_address: ChecksumAddress, - token_id: int, - receiver_address: ChecksumAddress, - transaction_config, - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.drainERC1155( - token_address, token_id, receiver_address, transaction_config - ) - - def drain_erc20( - self, - token_address: ChecksumAddress, - receiver_address: ChecksumAddress, - transaction_config, - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.drainERC20( - token_address, receiver_address, transaction_config - ) - - def get_terminus_address( - self, block_number: Optional[Union[str, int]] = "latest" - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.getTerminusAddress.call(block_identifier=block_number) - - def get_terminus_main_admin_pool_id( - self, block_number: Optional[Union[str, int]] = "latest" - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.getTerminusMainAdminPoolId.call( - block_identifier=block_number - ) - - def get_terminus_pool_controller_pool( - self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.getTerminusPoolControllerPool.call( - pool_id, block_identifier=block_number - ) - - def init_terminus_controller( - self, - terminus_address: ChecksumAddress, - _terminus_main_admin_pool_terminus_address: ChecksumAddress, - _terminus_main_admin_pool_id: int, - transaction_config, - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.initTerminusController( - terminus_address, - _terminus_main_admin_pool_terminus_address, - _terminus_main_admin_pool_id, - transaction_config, - ) - - def is_approved_for_pool( - self, - pool_id: int, - operator: ChecksumAddress, - block_number: Optional[Union[str, int]] = "latest", - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.isApprovedForPool.call( - pool_id, operator, block_identifier=block_number - ) - - def mint( - self, - to: ChecksumAddress, - pool_id: int, - amount: int, - data: bytes, - transaction_config, - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.mint(to, pool_id, amount, data, transaction_config) - - def mint_batch( - self, - to: ChecksumAddress, - pool_i_ds: List, - amounts: List, - data: bytes, - transaction_config, - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.mintBatch(to, pool_i_ds, amounts, data, transaction_config) - - def pool_mint_batch( - self, id: int, to_addresses: List, amounts: List, transaction_config - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.poolMintBatch( - id, to_addresses, amounts, transaction_config - ) - - def set_contract_uri(self, _contract_uri: str, transaction_config) -> Any: - self.assert_contract_is_instantiated() - return self.contract.setContractURI(_contract_uri, transaction_config) - - def set_controller( - self, new_controller: ChecksumAddress, transaction_config - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.setController(new_controller, transaction_config) - - def set_pool_control_permissions( - self, - pool_id: int, - terminus_address: ChecksumAddress, - pool_controller_pool_id: int, - transaction_config, - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.setPoolControlPermissions( - pool_id, terminus_address, pool_controller_pool_id, transaction_config - ) - - def set_pool_controller( - self, pool_id: int, new_controller: ChecksumAddress, transaction_config - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.setPoolController( - pool_id, new_controller, transaction_config - ) - - def set_uri(self, pool_id: int, pool_uri: str, transaction_config) -> Any: - self.assert_contract_is_instantiated() - return self.contract.setURI(pool_id, pool_uri, transaction_config) - - def terminus_controller( - self, block_number: Optional[Union[str, int]] = "latest" - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.terminusController.call(block_identifier=block_number) - - def terminus_pool_capacity( - self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.terminusPoolCapacity.call( - pool_id, block_identifier=block_number - ) - - def terminus_pool_controller( - self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.terminusPoolController.call( - pool_id, block_identifier=block_number - ) - - def terminus_pool_supply( - self, pool_id: int, block_number: Optional[Union[str, int]] = "latest" - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.terminusPoolSupply.call( - pool_id, block_identifier=block_number - ) - - def total_pools(self, block_number: Optional[Union[str, int]] = "latest") -> Any: - self.assert_contract_is_instantiated() - return self.contract.totalPools.call(block_identifier=block_number) - - def unapprove_for_pool( - self, pool_id: int, operator: ChecksumAddress, transaction_config - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.unapproveForPool(pool_id, operator, transaction_config) - - def withdraw_erc1155( - self, - token_address: ChecksumAddress, - token_id: int, - amount: int, - receiver_address: ChecksumAddress, - transaction_config, - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.withdrawERC1155( - token_address, token_id, amount, receiver_address, transaction_config - ) - - def withdraw_erc20( - self, - token_address: ChecksumAddress, - amount: int, - receiver_address: ChecksumAddress, - transaction_config, - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.withdrawERC20( - token_address, amount, receiver_address, transaction_config - ) - - def withdraw_erc721( - self, - token_address: ChecksumAddress, - token_id: int, - receiver_address: ChecksumAddress, - transaction_config, - ) -> Any: - self.assert_contract_is_instantiated() - return self.contract.withdrawERC721( - token_address, token_id, receiver_address, transaction_config - ) - - -def get_transaction_config(args: argparse.Namespace) -> Dict[str, Any]: - signer = network.accounts.load(args.sender, args.password) - transaction_config: Dict[str, Any] = {"from": signer} - if args.gas_price is not None: - transaction_config["gas_price"] = args.gas_price - if args.max_fee_per_gas is not None: - transaction_config["max_fee"] = args.max_fee_per_gas - if args.max_priority_fee_per_gas is not None: - transaction_config["priority_fee"] = args.max_priority_fee_per_gas - if args.confirmations is not None: - transaction_config["required_confs"] = args.confirmations - if args.nonce is not None: - transaction_config["nonce"] = args.nonce - return transaction_config - - -def add_default_arguments(parser: argparse.ArgumentParser, transact: bool) -> None: - parser.add_argument( - "--network", required=True, help="Name of brownie network to connect to" - ) - parser.add_argument( - "--address", required=False, help="Address of deployed contract to connect to" - ) - if not transact: - parser.add_argument( - "--block-number", - required=False, - type=int, - help="Call at the given block number, defaults to latest", - ) - return - parser.add_argument( - "--sender", required=True, help="Path to keystore file for transaction sender" - ) - parser.add_argument( - "--password", - required=False, - help="Password to keystore file (if you do not provide it, you will be prompted for it)", - ) - parser.add_argument( - "--gas-price", default=None, help="Gas price at which to submit transaction" - ) - parser.add_argument( - "--max-fee-per-gas", - default=None, - help="Max fee per gas for EIP1559 transactions", - ) - parser.add_argument( - "--max-priority-fee-per-gas", - default=None, - help="Max priority fee per gas for EIP1559 transactions", - ) - parser.add_argument( - "--confirmations", - type=int, - default=None, - help="Number of confirmations to await before considering a transaction completed", - ) - parser.add_argument( - "--nonce", type=int, default=None, help="Nonce for the transaction (optional)" - ) - parser.add_argument( - "--value", default=None, help="Value of the transaction in wei(optional)" - ) - parser.add_argument("--verbose", action="store_true", help="Print verbose output") - - -def handle_deploy(args: argparse.Namespace) -> None: - network.connect(args.network) - transaction_config = get_transaction_config(args) - contract = TerminusControllerFacet(None) - result = contract.deploy(transaction_config=transaction_config) - print(result) - if args.verbose: - print(result.info()) - - -def handle_verify_contract(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - result = contract.verify_contract() - print(result) - - -def handle_approve_for_pool(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.approve_for_pool( - pool_id=args.pool_id, - operator=args.operator, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_balance_of(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - result = contract.balance_of( - account=args.account, id=args.id, block_number=args.block_number - ) - print(result) - - -def handle_burn(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.burn( - from_=args.from_arg, - pool_id=args.pool_id, - amount=args.amount, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_contract_uri(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - result = contract.contract_uri(block_number=args.block_number) - print(result) - - -def handle_create_pool_v1(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.create_pool_v1( - _capacity=args.capacity_arg, - _transferable=args.transferable_arg, - _burnable=args.burnable_arg, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_create_simple_pool(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.create_simple_pool( - _capacity=args.capacity_arg, transaction_config=transaction_config - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_drain_erc1155(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.drain_erc1155( - token_address=args.token_address, - token_id=args.token_id, - receiver_address=args.receiver_address, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_drain_erc20(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.drain_erc20( - token_address=args.token_address, - receiver_address=args.receiver_address, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_get_terminus_address(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - result = contract.get_terminus_address(block_number=args.block_number) - print(result) - - -def handle_get_terminus_main_admin_pool_id(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - result = contract.get_terminus_main_admin_pool_id(block_number=args.block_number) - print(result) - - -def handle_get_terminus_pool_controller_pool(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - result = contract.get_terminus_pool_controller_pool( - pool_id=args.pool_id, block_number=args.block_number - ) - print(result) - - -def handle_init_terminus_controller(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.init_terminus_controller( - terminus_address=args.terminus_address, - _terminus_main_admin_pool_terminus_address=args.terminus_main_admin_pool_terminus_address_arg, - _terminus_main_admin_pool_id=args.terminus_main_admin_pool_id_arg, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_is_approved_for_pool(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - result = contract.is_approved_for_pool( - pool_id=args.pool_id, operator=args.operator, block_number=args.block_number - ) - print(result) - - -def handle_mint(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.mint( - to=args.to, - pool_id=args.pool_id, - amount=args.amount, - data=args.data, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_mint_batch(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.mint_batch( - to=args.to, - pool_i_ds=args.pool_i_ds, - amounts=args.amounts, - data=args.data, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_pool_mint_batch(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.pool_mint_batch( - id=args.id, - to_addresses=args.to_addresses, - amounts=args.amounts, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_set_contract_uri(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.set_contract_uri( - _contract_uri=args.contract_uri_arg, transaction_config=transaction_config - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_set_controller(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.set_controller( - new_controller=args.new_controller, transaction_config=transaction_config - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_set_pool_control_permissions(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.set_pool_control_permissions( - pool_id=args.pool_id, - terminus_address=args.terminus_address, - pool_controller_pool_id=args.pool_controller_pool_id, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_set_pool_controller(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.set_pool_controller( - pool_id=args.pool_id, - new_controller=args.new_controller, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_set_uri(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.set_uri( - pool_id=args.pool_id, - pool_uri=args.pool_uri, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_terminus_controller(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - result = contract.terminus_controller(block_number=args.block_number) - print(result) - - -def handle_terminus_pool_capacity(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - result = contract.terminus_pool_capacity( - pool_id=args.pool_id, block_number=args.block_number - ) - print(result) - - -def handle_terminus_pool_controller(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - result = contract.terminus_pool_controller( - pool_id=args.pool_id, block_number=args.block_number - ) - print(result) - - -def handle_terminus_pool_supply(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - result = contract.terminus_pool_supply( - pool_id=args.pool_id, block_number=args.block_number - ) - print(result) - - -def handle_total_pools(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - result = contract.total_pools(block_number=args.block_number) - print(result) - - -def handle_unapprove_for_pool(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.unapprove_for_pool( - pool_id=args.pool_id, - operator=args.operator, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_withdraw_erc1155(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.withdraw_erc1155( - token_address=args.token_address, - token_id=args.token_id, - amount=args.amount, - receiver_address=args.receiver_address, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_withdraw_erc20(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.withdraw_erc20( - token_address=args.token_address, - amount=args.amount, - receiver_address=args.receiver_address, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def handle_withdraw_erc721(args: argparse.Namespace) -> None: - network.connect(args.network) - contract = TerminusControllerFacet(args.address) - transaction_config = get_transaction_config(args) - result = contract.withdraw_erc721( - token_address=args.token_address, - token_id=args.token_id, - receiver_address=args.receiver_address, - transaction_config=transaction_config, - ) - print(result) - if args.verbose: - print(result.info()) - - -def generate_cli() -> argparse.ArgumentParser: - parser = argparse.ArgumentParser(description="CLI for TerminusControllerFacet") - parser.set_defaults(func=lambda _: parser.print_help()) - subcommands = parser.add_subparsers() - - deploy_parser = subcommands.add_parser("deploy") - add_default_arguments(deploy_parser, True) - deploy_parser.set_defaults(func=handle_deploy) - - verify_contract_parser = subcommands.add_parser("verify-contract") - add_default_arguments(verify_contract_parser, False) - verify_contract_parser.set_defaults(func=handle_verify_contract) - - approve_for_pool_parser = subcommands.add_parser("approve-for-pool") - add_default_arguments(approve_for_pool_parser, True) - approve_for_pool_parser.add_argument( - "--pool-id", required=True, help="Type: uint256", type=int - ) - approve_for_pool_parser.add_argument( - "--operator", required=True, help="Type: address" - ) - approve_for_pool_parser.set_defaults(func=handle_approve_for_pool) - - balance_of_parser = subcommands.add_parser("balance-of") - add_default_arguments(balance_of_parser, False) - balance_of_parser.add_argument("--account", required=True, help="Type: address") - balance_of_parser.add_argument( - "--id", required=True, help="Type: uint256", type=int - ) - balance_of_parser.set_defaults(func=handle_balance_of) - - burn_parser = subcommands.add_parser("burn") - add_default_arguments(burn_parser, True) - burn_parser.add_argument("--from-arg", required=True, help="Type: address") - burn_parser.add_argument("--pool-id", required=True, help="Type: uint256", type=int) - burn_parser.add_argument("--amount", required=True, help="Type: uint256", type=int) - burn_parser.set_defaults(func=handle_burn) - - contract_uri_parser = subcommands.add_parser("contract-uri") - add_default_arguments(contract_uri_parser, False) - contract_uri_parser.set_defaults(func=handle_contract_uri) - - create_pool_v1_parser = subcommands.add_parser("create-pool-v1") - add_default_arguments(create_pool_v1_parser, True) - create_pool_v1_parser.add_argument( - "--capacity-arg", required=True, help="Type: uint256", type=int - ) - create_pool_v1_parser.add_argument( - "--transferable-arg", - required=True, - help="Type: bool", - type=boolean_argument_type, - ) - create_pool_v1_parser.add_argument( - "--burnable-arg", required=True, help="Type: bool", type=boolean_argument_type - ) - create_pool_v1_parser.set_defaults(func=handle_create_pool_v1) - - create_simple_pool_parser = subcommands.add_parser("create-simple-pool") - add_default_arguments(create_simple_pool_parser, True) - create_simple_pool_parser.add_argument( - "--capacity-arg", required=True, help="Type: uint256", type=int - ) - create_simple_pool_parser.set_defaults(func=handle_create_simple_pool) - - drain_erc1155_parser = subcommands.add_parser("drain-erc1155") - add_default_arguments(drain_erc1155_parser, True) - drain_erc1155_parser.add_argument( - "--token-address", required=True, help="Type: address" - ) - drain_erc1155_parser.add_argument( - "--token-id", required=True, help="Type: uint256", type=int - ) - drain_erc1155_parser.add_argument( - "--receiver-address", required=True, help="Type: address" - ) - drain_erc1155_parser.set_defaults(func=handle_drain_erc1155) - - drain_erc20_parser = subcommands.add_parser("drain-erc20") - add_default_arguments(drain_erc20_parser, True) - drain_erc20_parser.add_argument( - "--token-address", required=True, help="Type: address" - ) - drain_erc20_parser.add_argument( - "--receiver-address", required=True, help="Type: address" - ) - drain_erc20_parser.set_defaults(func=handle_drain_erc20) - - get_terminus_address_parser = subcommands.add_parser("get-terminus-address") - add_default_arguments(get_terminus_address_parser, False) - get_terminus_address_parser.set_defaults(func=handle_get_terminus_address) - - get_terminus_main_admin_pool_id_parser = subcommands.add_parser( - "get-terminus-main-admin-pool-id" - ) - add_default_arguments(get_terminus_main_admin_pool_id_parser, False) - get_terminus_main_admin_pool_id_parser.set_defaults( - func=handle_get_terminus_main_admin_pool_id - ) - - get_terminus_pool_controller_pool_parser = subcommands.add_parser( - "get-terminus-pool-controller-pool" - ) - add_default_arguments(get_terminus_pool_controller_pool_parser, False) - get_terminus_pool_controller_pool_parser.add_argument( - "--pool-id", required=True, help="Type: uint256", type=int - ) - get_terminus_pool_controller_pool_parser.set_defaults( - func=handle_get_terminus_pool_controller_pool - ) - - init_terminus_controller_parser = subcommands.add_parser("init-terminus-controller") - add_default_arguments(init_terminus_controller_parser, True) - init_terminus_controller_parser.add_argument( - "--terminus-address", required=True, help="Type: address" - ) - init_terminus_controller_parser.add_argument( - "--terminus-main-admin-pool-terminus-address-arg", - required=True, - help="Type: address", - ) - init_terminus_controller_parser.add_argument( - "--terminus-main-admin-pool-id-arg", - required=True, - help="Type: uint256", - type=int, - ) - init_terminus_controller_parser.set_defaults(func=handle_init_terminus_controller) - - is_approved_for_pool_parser = subcommands.add_parser("is-approved-for-pool") - add_default_arguments(is_approved_for_pool_parser, False) - is_approved_for_pool_parser.add_argument( - "--pool-id", required=True, help="Type: uint256", type=int - ) - is_approved_for_pool_parser.add_argument( - "--operator", required=True, help="Type: address" - ) - is_approved_for_pool_parser.set_defaults(func=handle_is_approved_for_pool) - - mint_parser = subcommands.add_parser("mint") - add_default_arguments(mint_parser, True) - mint_parser.add_argument("--to", required=True, help="Type: address") - mint_parser.add_argument("--pool-id", required=True, help="Type: uint256", type=int) - mint_parser.add_argument("--amount", required=True, help="Type: uint256", type=int) - mint_parser.add_argument( - "--data", required=True, help="Type: bytes", type=bytes_argument_type - ) - mint_parser.set_defaults(func=handle_mint) - - mint_batch_parser = subcommands.add_parser("mint-batch") - add_default_arguments(mint_batch_parser, True) - mint_batch_parser.add_argument("--to", required=True, help="Type: address") - mint_batch_parser.add_argument( - "--pool-i-ds", required=True, help="Type: uint256[]", nargs="+" - ) - mint_batch_parser.add_argument( - "--amounts", required=True, help="Type: uint256[]", nargs="+" - ) - mint_batch_parser.add_argument( - "--data", required=True, help="Type: bytes", type=bytes_argument_type - ) - mint_batch_parser.set_defaults(func=handle_mint_batch) - - pool_mint_batch_parser = subcommands.add_parser("pool-mint-batch") - add_default_arguments(pool_mint_batch_parser, True) - pool_mint_batch_parser.add_argument( - "--id", required=True, help="Type: uint256", type=int - ) - pool_mint_batch_parser.add_argument( - "--to-addresses", required=True, help="Type: address[]", nargs="+" - ) - pool_mint_batch_parser.add_argument( - "--amounts", required=True, help="Type: uint256[]", nargs="+" - ) - pool_mint_batch_parser.set_defaults(func=handle_pool_mint_batch) - - set_contract_uri_parser = subcommands.add_parser("set-contract-uri") - add_default_arguments(set_contract_uri_parser, True) - set_contract_uri_parser.add_argument( - "--contract-uri-arg", required=True, help="Type: string", type=str - ) - set_contract_uri_parser.set_defaults(func=handle_set_contract_uri) - - set_controller_parser = subcommands.add_parser("set-controller") - add_default_arguments(set_controller_parser, True) - set_controller_parser.add_argument( - "--new-controller", required=True, help="Type: address" - ) - set_controller_parser.set_defaults(func=handle_set_controller) - - set_pool_control_permissions_parser = subcommands.add_parser( - "set-pool-control-permissions" - ) - add_default_arguments(set_pool_control_permissions_parser, True) - set_pool_control_permissions_parser.add_argument( - "--pool-id", required=True, help="Type: uint256", type=int - ) - set_pool_control_permissions_parser.add_argument( - "--terminus-address", required=True, help="Type: address" - ) - set_pool_control_permissions_parser.add_argument( - "--pool-controller-pool-id", required=True, help="Type: uint256", type=int - ) - set_pool_control_permissions_parser.set_defaults( - func=handle_set_pool_control_permissions - ) - - set_pool_controller_parser = subcommands.add_parser("set-pool-controller") - add_default_arguments(set_pool_controller_parser, True) - set_pool_controller_parser.add_argument( - "--pool-id", required=True, help="Type: uint256", type=int - ) - set_pool_controller_parser.add_argument( - "--new-controller", required=True, help="Type: address" - ) - set_pool_controller_parser.set_defaults(func=handle_set_pool_controller) - - set_uri_parser = subcommands.add_parser("set-uri") - add_default_arguments(set_uri_parser, True) - set_uri_parser.add_argument( - "--pool-id", required=True, help="Type: uint256", type=int - ) - set_uri_parser.add_argument( - "--pool-uri", required=True, help="Type: string", type=str - ) - set_uri_parser.set_defaults(func=handle_set_uri) - - terminus_controller_parser = subcommands.add_parser("terminus-controller") - add_default_arguments(terminus_controller_parser, False) - terminus_controller_parser.set_defaults(func=handle_terminus_controller) - - terminus_pool_capacity_parser = subcommands.add_parser("terminus-pool-capacity") - add_default_arguments(terminus_pool_capacity_parser, False) - terminus_pool_capacity_parser.add_argument( - "--pool-id", required=True, help="Type: uint256", type=int - ) - terminus_pool_capacity_parser.set_defaults(func=handle_terminus_pool_capacity) - - terminus_pool_controller_parser = subcommands.add_parser("terminus-pool-controller") - add_default_arguments(terminus_pool_controller_parser, False) - terminus_pool_controller_parser.add_argument( - "--pool-id", required=True, help="Type: uint256", type=int - ) - terminus_pool_controller_parser.set_defaults(func=handle_terminus_pool_controller) - - terminus_pool_supply_parser = subcommands.add_parser("terminus-pool-supply") - add_default_arguments(terminus_pool_supply_parser, False) - terminus_pool_supply_parser.add_argument( - "--pool-id", required=True, help="Type: uint256", type=int - ) - terminus_pool_supply_parser.set_defaults(func=handle_terminus_pool_supply) - - total_pools_parser = subcommands.add_parser("total-pools") - add_default_arguments(total_pools_parser, False) - total_pools_parser.set_defaults(func=handle_total_pools) - - unapprove_for_pool_parser = subcommands.add_parser("unapprove-for-pool") - add_default_arguments(unapprove_for_pool_parser, True) - unapprove_for_pool_parser.add_argument( - "--pool-id", required=True, help="Type: uint256", type=int - ) - unapprove_for_pool_parser.add_argument( - "--operator", required=True, help="Type: address" - ) - unapprove_for_pool_parser.set_defaults(func=handle_unapprove_for_pool) - - withdraw_erc1155_parser = subcommands.add_parser("withdraw-erc1155") - add_default_arguments(withdraw_erc1155_parser, True) - withdraw_erc1155_parser.add_argument( - "--token-address", required=True, help="Type: address" - ) - withdraw_erc1155_parser.add_argument( - "--token-id", required=True, help="Type: uint256", type=int - ) - withdraw_erc1155_parser.add_argument( - "--amount", required=True, help="Type: uint256", type=int - ) - withdraw_erc1155_parser.add_argument( - "--receiver-address", required=True, help="Type: address" - ) - withdraw_erc1155_parser.set_defaults(func=handle_withdraw_erc1155) - - withdraw_erc20_parser = subcommands.add_parser("withdraw-erc20") - add_default_arguments(withdraw_erc20_parser, True) - withdraw_erc20_parser.add_argument( - "--token-address", required=True, help="Type: address" - ) - withdraw_erc20_parser.add_argument( - "--amount", required=True, help="Type: uint256", type=int - ) - withdraw_erc20_parser.add_argument( - "--receiver-address", required=True, help="Type: address" - ) - withdraw_erc20_parser.set_defaults(func=handle_withdraw_erc20) - - withdraw_erc721_parser = subcommands.add_parser("withdraw-erc721") - add_default_arguments(withdraw_erc721_parser, True) - withdraw_erc721_parser.add_argument( - "--token-address", required=True, help="Type: address" - ) - withdraw_erc721_parser.add_argument( - "--token-id", required=True, help="Type: uint256", type=int - ) - withdraw_erc721_parser.add_argument( - "--receiver-address", required=True, help="Type: address" - ) - withdraw_erc721_parser.set_defaults(func=handle_withdraw_erc721) - - return parser - - -def main() -> None: - parser = generate_cli() - args = parser.parse_args() - args.func(args) - - -if __name__ == "__main__": - main() diff --git a/cli/web3cli/core.py b/cli/web3cli/core.py index 4b05a01a..4de58ca6 100644 --- a/cli/web3cli/core.py +++ b/cli/web3cli/core.py @@ -24,6 +24,8 @@ CraftingFacet, GOFPFacet, InventoryFacet, + TerminusFacet, + TerminusInitializer, ) FACETS: Dict[str, Any] = { @@ -35,6 +37,7 @@ "CraftingFacet": CraftingFacet, "GOFPFacet": GOFPFacet, "InventoryFacet": InventoryFacet, + "TerminusFacet": TerminusFacet, } FACET_INIT_CALLDATA: Dict[str, str] = { @@ -47,6 +50,9 @@ "InventoryFacet": lambda address, *args: InventoryFacet.InventoryFacet( address ).contract.init.encode_input(*args), + "TerminusFacet": lambda address, *args: TerminusInitializer.TerminusInitializer( + address + ).contract.init.encode_input(*args), } DIAMOND_FACET_PRECEDENCE: List[str] = [ @@ -66,6 +72,7 @@ class EngineFeatures(Enum): DROPPER = "DropperFacet" GOFP = "GOFPFacet" INVENTORY = "InventoryFacet" + TERMINUS = "TerminusFacet" def feature_from_facet_name(facet_name: str) -> Optional[EngineFeatures]: @@ -79,12 +86,14 @@ def feature_from_facet_name(facet_name: str) -> Optional[EngineFeatures]: EngineFeatures.DROPPER: ["DropperFacet"], EngineFeatures.GOFP: ["GOFPFacet"], EngineFeatures.INVENTORY: ["InventoryFacet"], + EngineFeatures.TERMINUS: ["TerminusFacet"], } FEATURE_IGNORES: Dict[EngineFeatures, List[str]] = { EngineFeatures.DROPPER: {"methods": ["init"], "selectors": []}, EngineFeatures.GOFP: {"methods": ["init"], "selectors": []}, EngineFeatures.INVENTORY: {"methods": ["init"], "selectors": []}, + EngineFeatures.TERMINUS: {"methods": [], "selectors": []}, } FACET_ACTIONS: Dict[str, int] = {"add": 0, "replace": 1, "remove": 2} @@ -710,6 +719,67 @@ def inventory_gogogo( return deployment_info +def terminus_gogogo( + transaction_config: Dict[str, Any], + diamond_cut_address: Optional[str] = None, + diamond_address: Optional[str] = None, + diamond_loupe_address: Optional[str] = None, + ownership_address: Optional[str] = None, + terminus_facet_address: Optional[str] = None, + terminus_initializer_address: Optional[str] = None, + verify_contracts: Optional[bool] = False, +) -> Dict[str, Any]: + """ + Deploys an EIP2535 Diamond contract and a TerminusFacet and mounts the TerminusFacet onto the Diamond contract. + + Returns the addresses and attachments. + """ + deployment_info = diamond_gogogo( + owner_address=transaction_config["from"].address, + transaction_config=transaction_config, + diamond_cut_address=diamond_cut_address, + diamond_address=diamond_address, + diamond_loupe_address=diamond_loupe_address, + ownership_address=ownership_address, + verify_contracts=verify_contracts, + ) + + if terminus_facet_address is None: + terminus_facet = TerminusFacet.TerminusFacet(None) + terminus_facet.deploy(transaction_config=transaction_config) + else: + terminus_facet = TerminusFacet.TerminusFacet(terminus_facet_address) + + if terminus_initializer_address is None: + terminus_initializer = TerminusInitializer.TerminusInitializer(None) + terminus_initializer.deploy(transaction_config=transaction_config) + terminus_initializer_address = terminus_initializer.address + + deployment_info["contracts"]["TerminusFacet"] = terminus_facet.address + deployment_info["contracts"]["TerminusInitializer"] = terminus_initializer_address + + if verify_contracts: + try: + terminus_facet.verify_contract() + deployment_info["verified"].append("InventoryFacet") + except Exception as e: + deployment_info["verification_errors"].append(repr(e)) + + facet_cut( + deployment_info["contracts"]["Diamond"], + "TerminusFacet", + terminus_facet.address, + "add", + transaction_config, + initializer_address=terminus_initializer_address, + feature=EngineFeatures.TERMINUS, + initializer_args=[], + ) + deployment_info["attached"].append("TerminusFacet") + + return deployment_info + + def handle_facet_cut(args: argparse.Namespace) -> None: network.connect(args.network) diamond_address = args.address @@ -805,6 +875,25 @@ def handle_inventory_gogogo(args: argparse.Namespace) -> None: json.dump(result, sys.stdout, indent=4) +def handle_terminus_gogogo(args: argparse.Namespace) -> None: + network.connect(args.network) + transaction_config = TerminusFacet.get_transaction_config(args) + result = terminus_gogogo( + transaction_config=transaction_config, + diamond_cut_address=args.diamond_cut_address, + diamond_address=args.diamond_address, + diamond_loupe_address=args.diamond_loupe_address, + ownership_address=args.ownership_address, + terminus_facet_address=args.terminus_facet_address, + terminus_initializer_address=args.terminus_initializer_address, + verify_contracts=args.verify_contracts, + ) + if args.outfile is not None: + with args.outfile: + json.dump(result, args.outfile) + json.dump(result, sys.stdout, indent=4) + + def handle_crafting_gogogo(args: argparse.Namespace) -> None: network.connect(args.network) @@ -1044,6 +1133,61 @@ def generate_cli(): ) inventory_gogogo_parser.set_defaults(func=handle_inventory_gogogo) + terminus_gogogo_parser = subcommands.add_parser( + "terminus-gogogo", + description="Deploy Terminus diamond contract", + ) + Diamond.add_default_arguments(terminus_gogogo_parser, transact=True) + terminus_gogogo_parser.add_argument( + "--verify-contracts", + action="store_true", + help="Verify contracts", + ) + terminus_gogogo_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.", + ) + terminus_gogogo_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.", + ) + terminus_gogogo_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.", + ) + terminus_gogogo_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.", + ) + terminus_gogogo_parser.add_argument( + "--terminus-facet-address", + required=False, + default=None, + help="Address to deployed TerminusFacet. If provided, this command skips deployment of a new TerminusFacet. It mounts the existing TerminusFacet onto the Diamond.", + ) + terminus_gogogo_parser.add_argument( + "--terminus-initializer-address", + required=False, + default=None, + help="Address to deployed TerminusInitializer. If provided, this command skips deployment of a new TerminusInitializer. It uses the given TerminusInitializer to initialize the diamond upon the mounting of the TerminusFacet.", + ) + terminus_gogogo_parser.add_argument( + "-o", + "--outfile", + type=argparse.FileType("w"), + default=None, + help="(Optional) file to write deployed addresses to", + ) + terminus_gogogo_parser.set_defaults(func=handle_terminus_gogogo) + lootbox_gogogo_parser = subcommands.add_parser( "lootbox-gogogo", help="Deploys Lootbox contract", diff --git a/contracts/terminus/controller/LibTerminusController.sol b/contracts/terminus/controller/LibTerminusController.sol deleted file mode 100644 index 7ad1aec7..00000000 --- a/contracts/terminus/controller/LibTerminusController.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -/** - * Authors: Moonstream Engineering (engineering@moonstream.to) - * GitHub: https://github.com/bugout-dev/dao - * - */ - -pragma solidity ^0.8.9; - -struct TerminusPool { - address terminusAddress; - uint256 poolId; -} - -library LibTerminusController { - bytes32 constant TERMINUS_CONTROLLER_STORAGE_POSITION = - keccak256("moonstreamdao.eth.storage.terminus.controller"); - - struct TerminusControllerStorage { - address terminusAddress; - TerminusPool terminusMainAdminPool; - mapping(uint256 => TerminusPool) poolController; - } - - function terminusControllerStorage() - internal - pure - returns (TerminusControllerStorage storage es) - { - bytes32 position = TERMINUS_CONTROLLER_STORAGE_POSITION; - assembly { - es.slot := position - } - } -} diff --git a/contracts/terminus/controller/TerminusControllerFacet.sol b/contracts/terminus/controller/TerminusControllerFacet.sol deleted file mode 100644 index 06f1bea2..00000000 --- a/contracts/terminus/controller/TerminusControllerFacet.sol +++ /dev/null @@ -1,272 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -/** - * Authors: Moonstream Engineering (engineering@moonstream.to) - * GitHub: https://github.com/bugout-dev/dao - * - * This contract stands as a proxy for the Terminus contract - * with a ability to whitelist operators by using Terminus Pools - */ -import "@openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; -import "../TerminusFacet.sol"; -import "../TerminusPermissions.sol"; -import "./LibTerminusController.sol"; -import "../../TokenDrainerFacet.sol"; - -pragma solidity ^0.8.9; - -// Permissions: -// - Contract owner can change _TERMINUS_MAIN_ADMIN_POOL_ID (+ all other operations?) -// - Holder of _TERMINUS_MAIN_ADMIN_POOL_ID can change poolControllerPoolID, create pool (+ pool operations?) -// - PoolController can: mint/burn + setURI - -contract TerminusControllerFacet is TerminusPermissions, TokenDrainerFacet { - /** - * @dev Checks if the caller holds the Admin Pool token or PoolController of pool with poolID - * @param poolId The poolID to check - */ - modifier onlyPoolController(uint256 poolId) { - TerminusPool memory pool = LibTerminusController - .terminusControllerStorage() - .poolController[poolId]; - - TerminusPool memory adminPool = LibTerminusController - .terminusControllerStorage() - .terminusMainAdminPool; - require( - _holdsPoolToken(adminPool.terminusAddress, adminPool.poolId, 1) || - _holdsPoolToken(pool.terminusAddress, pool.poolId, 1), - "TerminusControllerFacet.onlyPoolController: Sender doens't hold pool controller token" - ); - _; - } - - /** - * @dev Checks if the caller holds the Admin Pool token - */ - modifier onlyMainAdmin() { - TerminusPool memory adminPool = LibTerminusController - .terminusControllerStorage() - .terminusMainAdminPool; - require( - _holdsPoolToken(adminPool.terminusAddress, adminPool.poolId, 1), - "TerminusControllerFacet.onlyPoolController: Sender doens't hold pool controller token" - ); - _; - } - - function initTerminusController( - address terminusAddress, - address _TERMINUS_MAIN_ADMIN_POOL_TERMINUS_ADDRESS, - uint256 _TERMINUS_MAIN_ADMIN_POOL_ID - ) public { - LibTerminusController.TerminusControllerStorage - storage ts = LibTerminusController.terminusControllerStorage(); - - ts.terminusMainAdminPool = TerminusPool( - _TERMINUS_MAIN_ADMIN_POOL_TERMINUS_ADDRESS, - _TERMINUS_MAIN_ADMIN_POOL_ID - ); - ts.terminusAddress = terminusAddress; - } - - function terminusContract() internal view returns (TerminusFacet) { - return - TerminusFacet( - LibTerminusController - .terminusControllerStorage() - .terminusAddress - ); - } - - function getTerminusPoolControllerPool( - uint256 poolId - ) public view returns (TerminusPool memory) { - return - LibTerminusController.terminusControllerStorage().poolController[ - poolId - ]; - } - - function getTerminusAddress() public view returns (address) { - return - LibTerminusController.terminusControllerStorage().terminusAddress; - } - - function getTerminusMainAdminPoolId() - public - view - returns (TerminusPool memory) - { - return - LibTerminusController - .terminusControllerStorage() - .terminusMainAdminPool; - } - - /** - * @dev Gives permission to the holder of the (poolControllerPoolId,terminusAddress) - * to mint/burn/setURI for the pool with poolId - */ - function setPoolControlPermissions( - uint256 poolId, - address terminusAddress, - uint256 poolControllerPoolId - ) public onlyMainAdmin { - LibTerminusController.terminusControllerStorage().poolController[ - poolId - ] = TerminusPool(terminusAddress, poolControllerPoolId); - } - - // PROXY FUNCTIONS: - - /** - * @dev Sets the controller of the terminus contract - */ - function setController(address newController) external { - LibDiamond.enforceIsContractOwner(); - terminusContract().setController(newController); - } - - function poolMintBatch( - uint256 id, - address[] memory toAddresses, - uint256[] memory amounts - ) public onlyPoolController(id) { - terminusContract().poolMintBatch(id, toAddresses, amounts); - } - - function terminusController() external view returns (address) { - return terminusContract().terminusController(); - } - - function contractURI() public view returns (string memory) { - return terminusContract().contractURI(); - } - - function setContractURI(string memory _contractURI) external onlyMainAdmin { - terminusContract().setContractURI(_contractURI); - } - - function setURI( - uint256 poolID, - string memory poolURI - ) external onlyPoolController(poolID) { - terminusContract().setURI(poolID, poolURI); - } - - function totalPools() external view returns (uint256) { - return terminusContract().totalPools(); - } - - function setPoolController( - uint256 poolID, - address newController - ) external onlyMainAdmin { - terminusContract().setPoolController(poolID, newController); - } - - function terminusPoolController( - uint256 poolID - ) external view returns (address) { - return terminusContract().terminusPoolController(poolID); - } - - function terminusPoolCapacity( - uint256 poolID - ) external view returns (uint256) { - return terminusContract().terminusPoolCapacity(poolID); - } - - function terminusPoolSupply( - uint256 poolID - ) external view returns (uint256) { - return terminusContract().terminusPoolSupply(poolID); - } - - function isApprovedForPool( - uint256 poolID, - address operator - ) public view returns (bool) { - return terminusContract().isApprovedForPool(poolID, operator); - } - - function approveForPool( - uint256 poolID, - address operator - ) external onlyPoolController(poolID) { - terminusContract().approveForPool(poolID, operator); - } - - function unapproveForPool( - uint256 poolID, - address operator - ) external onlyPoolController(poolID) { - terminusContract().unapproveForPool(poolID, operator); - } - - function _approvePoolCreationPayments() internal { - IERC20 paymentToken = IERC20(terminusContract().paymentToken()); - uint256 fee = terminusContract().poolBasePrice(); - uint256 contractBalance = paymentToken.balanceOf(address(this)); - require( - contractBalance >= fee, - "TerminusControllerFacet._getPoolCreationPayments: Not enough funds, pls transfet payment tokens to terminusController contract" - ); - paymentToken.approve(getTerminusAddress(), fee); - } - - function createSimplePool( - uint256 _capacity - ) external onlyMainAdmin returns (uint256) { - _approvePoolCreationPayments(); - return terminusContract().createSimplePool(_capacity); - } - - function createPoolV1( - uint256 _capacity, - bool _transferable, - bool _burnable - ) external onlyMainAdmin returns (uint256) { - _approvePoolCreationPayments(); - return - terminusContract().createPoolV1( - _capacity, - _transferable, - _burnable - ); - } - - function mint( - address to, - uint256 poolID, - uint256 amount, - bytes memory data - ) external onlyPoolController(poolID) { - terminusContract().mint(to, poolID, amount, data); - } - - function mintBatch( - address to, - uint256[] memory poolIDs, - uint256[] memory amounts, - bytes memory data - ) external onlyMainAdmin { - terminusContract().mintBatch(to, poolIDs, amounts, data); - } - - function burn( - address from, - uint256 poolID, - uint256 amount - ) external onlyPoolController(poolID) { - terminusContract().burn(from, poolID, amount); - } - - function balanceOf( - address account, - uint256 id - ) public view returns (uint256) { - return terminusContract().balanceOf(account, id); - } -} From 2791eac9c30093584b1e46dcae765f9c631d0ab2 Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Sun, 20 Aug 2023 21:43:46 -0700 Subject: [PATCH 08/12] Fixed imports (solidity) --- contracts/ControllableWithTerminus.sol | 15 ++--- contracts/Dropper.sol | 60 +++++++++---------- contracts/Dropper/DropperFacet.sol | 2 +- contracts/Lootbox.sol | 2 +- contracts/crafting/facets/CraftingFacet.sol | 17 +++--- contracts/inventory/InventoryFacet.sol | 2 +- .../GardenOfForkingPaths.sol | 4 +- 7 files changed, 50 insertions(+), 52 deletions(-) diff --git a/contracts/ControllableWithTerminus.sol b/contracts/ControllableWithTerminus.sol index 07d6229a..11ae261f 100644 --- a/contracts/ControllableWithTerminus.sol +++ b/contracts/ControllableWithTerminus.sol @@ -6,15 +6,17 @@ */ pragma solidity ^0.8.9; -import "@moonstream/contracts/terminus/TerminusFacet.sol"; +import {TerminusFacet} from "./terminus/TerminusFacet.sol"; import "@openzeppelin-contracts/contracts/access/Ownable.sol"; abstract contract ControllableWithTerminus is Ownable { TerminusFacet private terminus; uint256 public administratorPoolId; - constructor(address _terminusContractAddress, uint256 _administratorPoolId) - { + constructor( + address _terminusContractAddress, + uint256 _administratorPoolId + ) { terminus = TerminusFacet(_terminusContractAddress); administratorPoolId = _administratorPoolId; } @@ -32,10 +34,9 @@ abstract contract ControllableWithTerminus is Ownable { _; } - function changeAdministratorPoolId(uint256 _administratorPoolId) - public - onlyOwner - { + function changeAdministratorPoolId( + uint256 _administratorPoolId + ) public onlyOwner { administratorPoolId = _administratorPoolId; } diff --git a/contracts/Dropper.sol b/contracts/Dropper.sol index 8edac9d0..9f0fa3a1 100644 --- a/contracts/Dropper.sol +++ b/contracts/Dropper.sol @@ -7,7 +7,6 @@ pragma solidity ^0.8.9; -import "@moonstream/contracts/terminus/TerminusFacet.sol"; import "@openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin-contracts/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol"; @@ -19,6 +18,8 @@ import "@openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol" import "@openzeppelin-contracts/contracts/utils/cryptography/draft-EIP712.sol"; import "@openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol"; +import {TerminusFacet} from "./terminus/TerminusFacet.sol"; + /** * @title Moonstream Dropper * @author Moonstream Engineering (engineering@moonstream.to) @@ -143,11 +144,9 @@ contract Dropper is return NumClaims; } - function getClaim(uint256 claimId) - external - view - returns (ClaimableToken memory) - { + function getClaim( + uint256 claimId + ) external view returns (ClaimableToken memory) { return ClaimToken[claimId]; } @@ -160,27 +159,24 @@ contract Dropper is return IsClaimActive[claimId]; } - function setSignerForClaim(uint256 claimId, address signer) - public - onlyOwner - { + function setSignerForClaim( + uint256 claimId, + address signer + ) public onlyOwner { ClaimSigner[claimId] = signer; emit ClaimSignerChanged(claimId, signer); } - function getSignerForClaim(uint256 claimId) - external - view - returns (address) - { + function getSignerForClaim( + uint256 claimId + ) external view returns (address) { return ClaimSigner[claimId]; } - function getClaimStatus(uint256 claimId, address claimant) - external - view - returns (uint256) - { + function getClaimStatus( + uint256 claimId, + address claimant + ) external view returns (uint256) { return ClaimCompleted[claimId][claimant]; } @@ -280,19 +276,19 @@ contract Dropper is emit Claimed(claimId, msg.sender); } - function withdrawERC20(address tokenAddress, uint256 amount) - public - onlyOwner - { + function withdrawERC20( + address tokenAddress, + uint256 amount + ) public onlyOwner { IERC20 erc20Contract = IERC20(tokenAddress); erc20Contract.transfer(_msgSender(), amount); emit Withdrawal(msg.sender, ERC20_TYPE, tokenAddress, 0, amount); } - function withdrawERC721(address tokenAddress, uint256 tokenId) - public - onlyOwner - { + function withdrawERC721( + address tokenAddress, + uint256 tokenId + ) public onlyOwner { address _owner = owner(); IERC721 erc721Contract = IERC721(tokenAddress); erc721Contract.safeTransferFrom(address(this), _owner, tokenId, ""); @@ -335,10 +331,10 @@ contract Dropper is return ClaimURI[claimId]; } - function setClaimUri(uint256 claimId, string memory uri) - external - onlyOwner - { + function setClaimUri( + uint256 claimId, + string memory uri + ) external onlyOwner { ClaimURI[claimId] = uri; } } diff --git a/contracts/Dropper/DropperFacet.sol b/contracts/Dropper/DropperFacet.sol index c088fc5b..c6c846c4 100644 --- a/contracts/Dropper/DropperFacet.sol +++ b/contracts/Dropper/DropperFacet.sol @@ -7,7 +7,6 @@ pragma solidity ^0.8.9; -import {TerminusPermissions} from "@moonstream/contracts/terminus/TerminusPermissions.sol"; import "@openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin-contracts/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol"; @@ -21,6 +20,7 @@ import "../interfaces/ITerminus.sol"; import "../diamond/security/DiamondReentrancyGuard.sol"; import "../diamond/libraries/LibDiamond.sol"; import "../diamond/libraries/LibSignatures.sol"; +import {TerminusPermissions} from "../terminus/TerminusPermissions.sol"; /** * @title Moonstream Dropper diff --git a/contracts/Lootbox.sol b/contracts/Lootbox.sol index f67f68b0..0ba4b072 100644 --- a/contracts/Lootbox.sol +++ b/contracts/Lootbox.sol @@ -7,7 +7,6 @@ pragma solidity ^0.8.9; -import "@moonstream/contracts/terminus/TerminusFacet.sol"; import "@openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol"; import "@openzeppelin-contracts/contracts/access/Ownable.sol"; @@ -17,6 +16,7 @@ import "@openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol" import "./ControllableWithTerminus.sol"; import "./LootboxRandomness.sol"; +import {TerminusFacet} from "./terminus/TerminusFacet.sol"; /** * @title Moonstream Lootbox managing contract diff --git a/contracts/crafting/facets/CraftingFacet.sol b/contracts/crafting/facets/CraftingFacet.sol index 3a961c9d..1d439686 100644 --- a/contracts/crafting/facets/CraftingFacet.sol +++ b/contracts/crafting/facets/CraftingFacet.sol @@ -12,12 +12,12 @@ import "@openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnab import "@openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol"; import "@openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import "@openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol"; -import {TerminusPermissions} from "@moonstream/contracts/terminus/TerminusPermissions.sol"; import {MockTerminus} from "../../mock/MockTerminus.sol"; import {MockErc20} from "../../mock/MockErc20.sol"; import "../libraries/LibCrafting.sol"; import "../../diamond/libraries/LibDiamond.sol"; import "../../diamond/security/DiamondReentrancyGuard.sol"; +import {TerminusPermissions} from "../../terminus/TerminusPermissions.sol"; contract CraftingFacet is ERC1155Holder, @@ -49,9 +49,10 @@ contract CraftingFacet is _; } - function setTerminusAuth(address terminusAddress, uint256 tokenId) - external - { + function setTerminusAuth( + address terminusAddress, + uint256 tokenId + ) external { LibDiamond.enforceIsContractOwner(); LibCrafting.CraftingStorage storage cs = LibCrafting.craftingStorage(); cs.authTerminusAddress = terminusAddress; @@ -66,10 +67,10 @@ contract CraftingFacet is emit RecipeCreated(0, recipe, msg.sender); } - function updateRecipe(uint256 recipeId, Recipe calldata recipe) - external - onlyAuthorizedAddress - { + function updateRecipe( + uint256 recipeId, + Recipe calldata recipe + ) external onlyAuthorizedAddress { LibCrafting.CraftingStorage storage cs = LibCrafting.craftingStorage(); cs.recipes[recipeId] = recipe; emit RecipeUpdated(recipeId, recipe, msg.sender); diff --git a/contracts/inventory/InventoryFacet.sol b/contracts/inventory/InventoryFacet.sol index 39c1ae15..14308f91 100644 --- a/contracts/inventory/InventoryFacet.sol +++ b/contracts/inventory/InventoryFacet.sol @@ -7,7 +7,6 @@ pragma solidity ^0.8.0; -import {TerminusPermissions} from "@moonstream/contracts/terminus/TerminusPermissions.sol"; import "@openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import "@openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol"; import "@openzeppelin-contracts/contracts/token/ERC721/IERC721.sol"; @@ -16,6 +15,7 @@ import "@openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol"; import "../diamond/libraries/LibDiamond.sol"; import {DiamondReentrancyGuard} from "../diamond/security/DiamondReentrancyGuard.sol"; import {Slot, EquippedItem, IInventory} from "./IInventory.sol"; +import {TerminusPermissions} from "../terminus/TerminusPermissions.sol"; /** LibInventory defines the storage structure used by the Inventory contract as a facet for an EIP-2535 Diamond diff --git a/contracts/mechanics/garden-of-forking-paths/GardenOfForkingPaths.sol b/contracts/mechanics/garden-of-forking-paths/GardenOfForkingPaths.sol index 83910477..4de6c596 100644 --- a/contracts/mechanics/garden-of-forking-paths/GardenOfForkingPaths.sol +++ b/contracts/mechanics/garden-of-forking-paths/GardenOfForkingPaths.sol @@ -7,14 +7,14 @@ pragma solidity ^0.8.0; -import {TerminusFacet} from "@moonstream/contracts/terminus/TerminusFacet.sol"; -import {TerminusPermissions} from "@moonstream/contracts/terminus/TerminusPermissions.sol"; import "@openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol"; 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 "../../diamond/libraries/LibDiamond.sol"; import "../../diamond/security/DiamondReentrancyGuard.sol"; +import {TerminusFacet} from "../../terminus/TerminusFacet.sol"; +import {TerminusPermissions} from "../../terminus/TerminusPermissions.sol"; struct Session { address playerTokenAddress; From 364c5c31e1e06d114d957d22bd813e716049dc80 Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Sun, 20 Aug 2023 21:59:48 -0700 Subject: [PATCH 09/12] Migrated over Terminus tests --- cli/web3cli/test_terminus.py | 1141 ++++++++++++++++++++++++++++++++++ 1 file changed, 1141 insertions(+) create mode 100644 cli/web3cli/test_terminus.py diff --git a/cli/web3cli/test_terminus.py b/cli/web3cli/test_terminus.py new file mode 100644 index 00000000..74020b15 --- /dev/null +++ b/cli/web3cli/test_terminus.py @@ -0,0 +1,1141 @@ +from typing import List +import unittest + +from brownie import accounts, network +from brownie.exceptions import VirtualMachineError + +from . import MockErc20, TerminusFacet +from .core import terminus_gogogo + + +class TerminusTestCase(unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + try: + network.connect() + except: + pass + + cls.deployment_info = terminus_gogogo({"from": accounts[0]}) + cls.terminus = TerminusFacet.TerminusFacet( + cls.deployment_info["contracts"]["Diamond"] + ) + + cls.erc20 = MockErc20.MockErc20(None) + cls.erc20.deploy("test", "test", {"from": accounts[0]}) + + +class TestDeployment(TerminusTestCase): + def test_deployment(self): + controller = self.terminus.terminus_controller() + self.assertEqual(controller, accounts[0].address) + + +class TestController(TerminusTestCase): + def test_set_controller_fails_when_not_called_by_controller(self): + with self.assertRaises(VirtualMachineError): + self.terminus.set_controller(accounts[1].address, {"from": accounts[1]}) + + def test_set_controller_fails_when_not_called_by_controller_even_if_they_change_to_existing_controller( + self, + ): + with self.assertRaises(VirtualMachineError): + self.terminus.set_controller(accounts[0].address, {"from": accounts[1]}) + + def test_set_controller(self): + self.assertEqual(self.terminus.terminus_controller(), accounts[0].address) + self.terminus.set_controller(accounts[3].address, {"from": accounts[0]}) + self.assertEqual(self.terminus.terminus_controller(), accounts[3].address) + self.terminus.set_controller(accounts[0].address, {"from": accounts[3]}) + self.assertEqual(self.terminus.terminus_controller(), accounts[0].address) + + +class TestContractURI(TerminusTestCase): + def test_contract_uri(self): + contract_uri = self.terminus.contract_uri() + self.assertEqual(contract_uri, "") + + self.terminus.set_contract_uri("https://example.com", {"from": accounts[0]}) + + contract_uri = self.terminus.contract_uri() + self.assertEqual(contract_uri, "https://example.com") + + +class TestSimplePoolCreation(TerminusTestCase): + def test_create_simple_pool(self): + self.terminus.set_payment_token(self.erc20.address, {"from": accounts[0]}) + payment_token = self.terminus.payment_token() + self.assertEqual(payment_token, self.erc20.address) + + self.terminus.set_pool_base_price(1000, {"from": accounts[0]}) + pool_base_price = self.terminus.pool_base_price() + self.assertEqual(pool_base_price, 1000) + + self.terminus.set_controller(accounts[1].address, {"from": accounts[0]}) + + self.erc20.mint(accounts[1], 1000, {"from": accounts[0]}) + initial_payer_balance = self.erc20.balance_of(accounts[1].address) + initial_terminus_balance = self.erc20.balance_of(self.terminus.address) + initial_controller_balance = self.erc20.balance_of(accounts[1].address) + + self.erc20.approve(self.terminus.address, 1000, {"from": accounts[1]}) + + initial_total_pools = self.terminus.total_pools() + + self.terminus.create_simple_pool(10, {"from": accounts[1]}) + + final_total_pools = self.terminus.total_pools() + self.assertEqual(final_total_pools, initial_total_pools + 1) + + final_payer_balance = self.erc20.balance_of(accounts[1].address) + intermediate_terminus_balance = self.erc20.balance_of(self.terminus.address) + intermediate_controller_balance = self.erc20.balance_of(accounts[1].address) + self.assertEqual(final_payer_balance, initial_payer_balance - 1000) + self.assertEqual(intermediate_terminus_balance, initial_terminus_balance + 1000) + self.assertEqual( + intermediate_controller_balance, initial_controller_balance - 1000 + ) + + with self.assertRaises(Exception): + self.terminus.withdraw_payments( + accounts[0].address, 1000, {"from": accounts[0]} + ) + + with self.assertRaises(Exception): + self.terminus.withdraw_payments( + accounts[1].address, 1000, {"from": accounts[0]} + ) + + with self.assertRaises(Exception): + self.terminus.withdraw_payments( + accounts[0].address, 1000, {"from": accounts[1]} + ) + + self.terminus.withdraw_payments( + accounts[1].address, 1000, {"from": accounts[1]} + ) + + final_terminus_balance = self.erc20.balance_of(self.terminus.address) + final_controller_balance = self.erc20.balance_of(accounts[1].address) + self.assertEqual(final_terminus_balance, intermediate_terminus_balance - 1000) + self.assertEqual( + final_controller_balance, intermediate_controller_balance + 1000 + ) + + with self.assertRaises(Exception): + self.terminus.withdraw_payments( + accounts[0].address, + final_terminus_balance + 1000, + {"from": accounts[0]}, + ) + + pool_controller = self.terminus.terminus_pool_controller(final_total_pools) + self.assertEqual(pool_controller, accounts[1].address) + + pool_capacity = self.terminus.terminus_pool_capacity(final_total_pools) + self.assertEqual(pool_capacity, 10) + + +class TestPoolOperations(TerminusTestCase): + @classmethod + def setUpClass(cls) -> None: + super().setUpClass() + cls.erc20 = MockErc20.MockErc20(None) + cls.erc20.deploy("test", "test", {"from": accounts[0]}) + cls.terminus.set_payment_token(cls.erc20.address, {"from": accounts[0]}) + cls.terminus.set_pool_base_price(1000, {"from": accounts[0]}) + cls.erc20.mint(accounts[1], 1000000, {"from": accounts[0]}) + cls.erc20.approve(cls.terminus.address, 1000000, {"from": accounts[1]}) + + cls.terminus.set_controller(accounts[1].address, {"from": accounts[0]}) + + def setUp(self) -> None: + self.terminus.create_simple_pool(10, {"from": accounts[1]}) + + def test_set_pool_controller(self): + pool_id = self.terminus.total_pools() + old_controller = accounts[1] + new_controller = accounts[2] + + current_controller_address = self.terminus.terminus_pool_controller(pool_id) + self.assertEqual(current_controller_address, old_controller.address) + + with self.assertRaises(Exception): + self.terminus.set_pool_controller( + pool_id, new_controller.address, {"from": new_controller} + ) + current_controller_address = self.terminus.terminus_pool_controller(pool_id) + self.assertEqual(current_controller_address, old_controller.address) + + self.terminus.set_pool_controller( + pool_id, new_controller.address, {"from": old_controller} + ) + current_controller_address = self.terminus.terminus_pool_controller(pool_id) + self.assertEqual(current_controller_address, new_controller.address) + + with self.assertRaises(Exception): + self.terminus.set_pool_controller( + pool_id, old_controller.address, {"from": old_controller} + ) + current_controller_address = self.terminus.terminus_pool_controller(pool_id) + self.assertEqual(current_controller_address, new_controller.address) + + self.terminus.set_pool_controller( + pool_id, old_controller.address, {"from": new_controller} + ) + current_controller_address = self.terminus.terminus_pool_controller(pool_id) + self.assertEqual(current_controller_address, old_controller.address) + + def test_mint(self): + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(balance, 1) + + supply = self.terminus.terminus_pool_supply(pool_id) + self.assertEqual(supply, 1) + + def test_mint_fails_if_it_exceeds_capacity(self): + pool_id = self.terminus.total_pools() + with self.assertRaises(Exception): + self.terminus.mint(accounts[2], pool_id, 11, b"", {"from": accounts[1]}) + + balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(balance, 0) + + supply = self.terminus.terminus_pool_supply(pool_id) + self.assertEqual(supply, 0) + + def test_mint_batch(self): + pool_id = self.terminus.total_pools() + self.terminus.mint_batch( + accounts[2].address, + pool_i_ds=[pool_id], + amounts=[1], + data=b"", + transaction_config={"from": accounts[1]}, + ) + + balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(balance, 1) + + supply = self.terminus.terminus_pool_supply(pool_id) + self.assertEqual(supply, 1) + + def test_mint_batch_with_approval(self): + pool_id = self.terminus.total_pools() + + self.assertFalse(self.terminus.is_approved_for_pool(pool_id, accounts[3])) + self.assertFalse(self.terminus.is_approved_for_pool(pool_id - 1, accounts[3])) + balances_before = [ + self.terminus.balance_of(accounts[2].address, pool_id), + self.terminus.balance_of(accounts[2].address, pool_id - 1), + ] + supply_before = [ + self.terminus.terminus_pool_supply(pool_id), + self.terminus.terminus_pool_supply(pool_id - 1), + ] + self.terminus.approve_for_pool(pool_id, accounts[3], {"from": accounts[1]}) + with self.assertRaises(Exception): + self.terminus.mint_batch( + accounts[2].address, + pool_i_ds=[pool_id, pool_id - 1], + amounts=[1, 1], + data=b"", + transaction_config={"from": accounts[3]}, + ) + + self.terminus.approve_for_pool(pool_id - 1, accounts[3], {"from": accounts[1]}) + + self.terminus.mint_batch( + accounts[2].address, + pool_i_ds=[pool_id, pool_id - 1], + amounts=[1, 1], + data=b"", + transaction_config={"from": accounts[3]}, + ) + + self.assertEqual( + self.terminus.balance_of(accounts[2].address, pool_id), + balances_before[0] + 1, + ) + self.assertEqual( + self.terminus.balance_of(accounts[2].address, pool_id - 1), + balances_before[1] + 1, + ) + + self.assertEqual( + self.terminus.terminus_pool_supply(pool_id), supply_before[0] + 1 + ) + self.assertEqual( + self.terminus.terminus_pool_supply(pool_id - 1), + supply_before[1] + 1, + ) + + def test_mint_batch_fails_if_it_exceeds_capacity(self): + capacity = 10 + self.terminus.create_pool_v1(capacity, True, True, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + with self.assertRaises(Exception): + self.terminus.mint_batch( + accounts[2].address, + pool_i_ds=[pool_id, pool_id], + amounts=[int(capacity / 2) + 1, int(capacity / 2) + 1], + data=b"", + transaction_config={"from": accounts[1]}, + ) + + balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(balance, 0) + + supply = self.terminus.terminus_pool_supply(pool_id) + self.assertEqual(supply, 0) + + def test_mint_batch_fails_if_it_exceeds_capacity_one_at_a_time(self): + capacity = 10 + self.terminus.create_pool_v1(capacity, True, True, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + with self.assertRaises(Exception): + self.terminus.mint_batch( + accounts[2].address, + pool_i_ds=[pool_id for _ in range(capacity + 1)], + amounts=[1 for _ in range(capacity + 1)], + data=b"", + transaction_config={"from": accounts[1]}, + ) + + balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(balance, 0) + + supply = self.terminus.terminus_pool_supply(pool_id) + self.assertEqual(supply, 0) + + def test_pool_mint_batch(self): + pool_id = self.terminus.total_pools() + target_accounts = [account.address for account in accounts[:5]] + target_amounts = [1 for _ in accounts[:5]] + num_accounts = len(accounts[:5]) + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_balances: List[int] = [] + for account in accounts[:5]: + initial_balances.append(self.terminus.balance_of(account.address, pool_id)) + self.terminus.pool_mint_batch( + pool_id, target_accounts, target_amounts, {"from": accounts[1]} + ) + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply + num_accounts) + for i, account in enumerate(accounts[:5]): + final_balance = self.terminus.balance_of(account.address, pool_id) + self.assertEqual(final_balance, initial_balances[i] + 1) + + def test_pool_mint_batch_as_contract_controller_not_pool_controller(self): + pool_id = self.terminus.total_pools() + target_accounts = [account.address for account in accounts[:5]] + target_amounts = [1 for _ in accounts[:5]] + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_balances: List[int] = [] + for account in accounts[:5]: + initial_balances.append(self.terminus.balance_of(account.address, pool_id)) + with self.assertRaises(Exception): + self.terminus.pool_mint_batch( + pool_id, target_accounts, target_amounts, {"from": accounts[0]} + ) + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply) + for i, account in enumerate(accounts[:5]): + final_balance = self.terminus.balance_of(account.address, pool_id) + self.assertEqual(final_balance, initial_balances[i]) + + def test_pool_mint_batch_as_unauthorized_third_party(self): + pool_id = self.terminus.total_pools() + target_accounts = [account.address for account in accounts[:5]] + target_amounts = [1 for _ in accounts[:5]] + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_balances: List[int] = [] + for account in accounts[:5]: + initial_balances.append(self.terminus.balance_of(account.address, pool_id)) + with self.assertRaises(Exception): + self.terminus.pool_mint_batch( + pool_id, target_accounts, target_amounts, {"from": accounts[2]} + ) + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply) + for i, account in enumerate(accounts[:5]): + final_balance = self.terminus.balance_of(account.address, pool_id) + self.assertEqual(final_balance, initial_balances[i]) + + def test_pool_mint_with_pool_approval(self): + self.terminus.create_pool_v1(10, False, False, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + + self.assertFalse( + self.terminus.is_approved_for_pool(pool_id, accounts[2].address) + ) + with self.assertRaises(Exception): + self.terminus.mint( + accounts[2].address, pool_id, 1, b"", {"from": accounts[2]} + ) + + self.terminus.approve_for_pool( + pool_id, accounts[2].address, {"from": accounts[1]} + ) + supply_0 = self.terminus.terminus_pool_supply(pool_id) + balance_0 = self.terminus.balance_of(accounts[2].address, pool_id) + self.terminus.mint(accounts[2].address, pool_id, 1, b"", {"from": accounts[1]}) + balance_1 = self.terminus.balance_of(accounts[2].address, pool_id) + supply_1 = self.terminus.terminus_pool_supply(pool_id) + + self.assertEqual(balance_1, balance_0 + 1) + self.assertEqual(supply_0 + 1, supply_1) + + def test_pool_mint_batch_with_approval(self): + pool_id = self.terminus.total_pools() + target_accounts = [account.address for account in accounts[:5]] + target_amounts = [1 for _ in accounts[:5]] + num_accounts = len(accounts[:5]) + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_balances: List[int] = [] + for account in accounts[:5]: + initial_balances.append(self.terminus.balance_of(account.address, pool_id)) + + self.assertFalse( + self.terminus.is_approved_for_pool(pool_id, accounts[2].address) + ) + with self.assertRaises(Exception): + self.terminus.pool_mint_batch( + pool_id, target_accounts, target_amounts, {"from": accounts[2]} + ) + self.terminus.approve_for_pool( + pool_id, accounts[2].address, {"from": accounts[1]} + ) + self.terminus.pool_mint_batch( + pool_id, target_accounts, target_amounts, {"from": accounts[2]} + ) + + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply + num_accounts) + for i, account in enumerate(accounts[:5]): + final_balance = self.terminus.balance_of(account.address, pool_id) + self.assertEqual(final_balance, initial_balances[i] + 1) + + def test_transfer(self): + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + initial_receiver_balance = self.terminus.balance_of( + accounts[3].address, pool_id + ) + + self.terminus.safe_transfer_from( + accounts[2].address, + accounts[3].address, + pool_id, + 1, + b"", + {"from": accounts[2]}, + ) + + final_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + final_receiver_balance = self.terminus.balance_of(accounts[3].address, pool_id) + + self.assertEqual(final_sender_balance, initial_sender_balance - 1) + self.assertEqual(final_receiver_balance, initial_receiver_balance + 1) + + def test_transfer_as_pool_controller(self): + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + initial_receiver_balance = self.terminus.balance_of( + accounts[3].address, pool_id + ) + + self.terminus.safe_transfer_from( + accounts[2].address, + accounts[3].address, + pool_id, + 1, + b"", + {"from": accounts[1]}, + ) + + final_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + final_receiver_balance = self.terminus.balance_of(accounts[3].address, pool_id) + + self.assertEqual(final_sender_balance, initial_sender_balance - 1) + self.assertEqual(final_receiver_balance, initial_receiver_balance + 1) + + def test_transfer_fails_as_controller_of_another_pool_with_no_approval(self): + """ + Hacken.io auditors claimed that an address that controlled *some* pool could effect transfers + on *any* pool. + + This test shows that this is not true. + + Exercises: + - safeTransferFrom + """ + # Ensure that accounts[1] is pool controller of *some* pool. + self.terminus.create_pool_v1(100, True, True, {"from": accounts[1]}) + controlled_pool_id = self.terminus.total_pools() + self.assertEqual( + self.terminus.terminus_pool_controller(controlled_pool_id), + accounts[1].address, + ) + + self.terminus.create_pool_v1(100, True, True, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + # Remove pool control from accounts[1] + self.terminus.set_pool_controller( + pool_id, accounts[4].address, {"from": accounts[1]} + ) + + initial_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + initial_receiver_balance = self.terminus.balance_of( + accounts[3].address, pool_id + ) + + with self.assertRaises(VirtualMachineError): + self.terminus.safe_transfer_from( + accounts[2].address, + accounts[3].address, + pool_id, + 1, + b"", + {"from": accounts[1]}, + ) + + final_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + final_receiver_balance = self.terminus.balance_of(accounts[3].address, pool_id) + + self.assertEqual(final_sender_balance, initial_sender_balance) + self.assertEqual(final_receiver_balance, initial_receiver_balance) + + def test_transfer_fails_as_terminus_controller_with_no_approval(self): + """ + Tests that neither Terminus controller *nor* pool controller can transfer a token on behalf of + another address without explicit approval (using safeTransferFrom). + + Exercises: + - safeTransferFrom + """ + self.assertEqual(self.terminus.terminus_controller(), accounts[1].address) + self.terminus.create_pool_v1(100, True, True, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + # Remove pool control from accounts[1] + self.terminus.set_pool_controller( + pool_id, accounts[4].address, {"from": accounts[1]} + ) + + initial_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + initial_receiver_balance = self.terminus.balance_of( + accounts[3].address, pool_id + ) + + with self.assertRaises(VirtualMachineError): + self.terminus.safe_transfer_from( + accounts[2].address, + accounts[3].address, + pool_id, + 1, + b"", + {"from": accounts[1]}, + ) + + final_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + final_receiver_balance = self.terminus.balance_of(accounts[3].address, pool_id) + + self.assertEqual(final_sender_balance, initial_sender_balance) + self.assertEqual(final_receiver_balance, initial_receiver_balance) + + def test_transfer_as_unauthorized_recipient(self): + self.terminus.create_pool_v1(2**256 - 1, True, True, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + initial_receiver_balance = self.terminus.balance_of( + accounts[3].address, pool_id + ) + + with self.assertRaises(Exception): + self.terminus.safe_transfer_from( + accounts[2].address, + accounts[3].address, + pool_id, + 1, + b"", + {"from": accounts[3]}, + ) + + final_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + final_receiver_balance = self.terminus.balance_of(accounts[3].address, pool_id) + + self.assertEqual(final_sender_balance, initial_sender_balance) + self.assertEqual(final_receiver_balance, initial_receiver_balance) + + def test_transfer_as_authorized_recipient(self): + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + initial_receiver_balance = self.terminus.balance_of( + accounts[3].address, pool_id + ) + + self.terminus.approve_for_pool( + pool_id, accounts[3].address, {"from": accounts[1]} + ) + self.terminus.safe_transfer_from( + accounts[2].address, + accounts[3].address, + pool_id, + 1, + b"", + {"from": accounts[3]}, + ) + + final_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + final_receiver_balance = self.terminus.balance_of(accounts[3].address, pool_id) + + self.assertEqual(final_sender_balance, initial_sender_balance - 1) + self.assertEqual(final_receiver_balance, initial_receiver_balance + 1) + + def test_transfer_as_approved_operator(self): + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + initial_receiver_balance = self.terminus.balance_of( + accounts[3].address, pool_id + ) + + # It is very important to revoke this approval from accounts[3] as accounts[3] tries to initiate + # transfers from accounts[2] in other tests. + self.terminus.set_approval_for_all( + accounts[3].address, True, {"from": accounts[2]} + ) + + try: + self.terminus.safe_transfer_from( + accounts[2].address, + accounts[3].address, + pool_id, + 1, + b"", + {"from": accounts[3]}, + ) + finally: + self.terminus.set_approval_for_all( + accounts[3].address, False, {"from": accounts[2]} + ) + + final_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + final_receiver_balance = self.terminus.balance_of(accounts[3].address, pool_id) + + self.assertEqual(final_sender_balance, initial_sender_balance - 1) + self.assertEqual(final_receiver_balance, initial_receiver_balance + 1) + + # Check that accounts[3] is no longer approved for all pools by accounts[2] (for other tests to) + # run correctly. + self.assertFalse( + self.terminus.is_approved_for_all(accounts[2].address, accounts[3].address) + ) + + def test_transfer_as_unauthorized_unrelated_party(self): + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + initial_receiver_balance = self.terminus.balance_of( + accounts[3].address, pool_id + ) + + with self.assertRaises(Exception): + self.terminus.safe_transfer_from( + accounts[2].address, + accounts[3].address, + pool_id, + 1, + b"", + {"from": accounts[4]}, + ) + + final_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + final_receiver_balance = self.terminus.balance_of(accounts[3].address, pool_id) + + self.assertEqual(final_sender_balance, initial_sender_balance) + self.assertEqual(final_receiver_balance, initial_receiver_balance) + + def test_transfer_as_authorized_unrelated_party(self): + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + initial_receiver_balance = self.terminus.balance_of( + accounts[3].address, pool_id + ) + + self.terminus.approve_for_pool( + pool_id, accounts[4].address, {"from": accounts[1]} + ) + self.terminus.safe_transfer_from( + accounts[2].address, + accounts[3].address, + pool_id, + 1, + b"", + {"from": accounts[4]}, + ) + + final_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + final_receiver_balance = self.terminus.balance_of(accounts[3].address, pool_id) + + self.assertEqual(final_sender_balance, initial_sender_balance - 1) + self.assertEqual(final_receiver_balance, initial_receiver_balance + 1) + + def test_burn_fails_as_token_owner(self): + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + with self.assertRaises(Exception): + self.terminus.burn(accounts[2].address, pool_id, 1, {"from": accounts[2]}) + + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + final_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply) + self.assertEqual(final_owner_balance, initial_owner_balance) + + def test_burn_fails_as_pool_controller(self): + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + with self.assertRaises(Exception): + self.terminus.burn(accounts[2].address, pool_id, 1, {"from": accounts[1]}) + + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + final_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply) + self.assertEqual(final_owner_balance, initial_owner_balance) + + def test_burn_fails_as_third_party(self): + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + with self.assertRaises(Exception): + self.terminus.burn(accounts[2].address, pool_id, 1, {"from": accounts[3]}) + + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + final_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply) + self.assertEqual(final_owner_balance, initial_owner_balance) + + def test_burn_fails_as_authorized_third_party(self): + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.terminus.approve_for_pool( + pool_id, accounts[3].address, {"from": accounts[1]} + ) + with self.assertRaises(Exception): + self.terminus.burn(accounts[2].address, pool_id, 1, {"from": accounts[3]}) + + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + final_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply) + self.assertEqual(final_owner_balance, initial_owner_balance) + + def test_pool_approval(self): + controller = accounts[1] + operator = accounts[2] + user = accounts[3] + + # TODO(zomglings): We should test the Terminus controller permissions on the same contract. + # Currently, controller is both pool controller AND Terminus controller. In a more proper test, + # these would be different accounts. + + # TODO(zomglings): Tested manually that changing burnable below from True to False results in + # the right reversion when we try to burn these tokens on-chain. This should be a separate + # test case that runs *automatically*. + self.terminus.create_pool_v1(100, True, True, {"from": controller}) + pool_id = self.terminus.total_pools() + self.terminus.mint(controller.address, pool_id, 5, "", {"from": controller}) + self.terminus.mint(operator.address, pool_id, 5, "", {"from": controller}) + self.terminus.mint(user.address, pool_id, 5, "", {"from": controller}) + + controller_balance_0 = self.terminus.balance_of(controller.address, pool_id) + operator_balance_0 = self.terminus.balance_of(operator.address, pool_id) + user_balance_0 = self.terminus.balance_of(user.address, pool_id) + + self.assertFalse(self.terminus.is_approved_for_pool(pool_id, operator.address)) + + with self.assertRaises(VirtualMachineError): + self.terminus.mint(controller.address, pool_id, 1, "", {"from": operator}) + + with self.assertRaises(VirtualMachineError): + self.terminus.mint(operator.address, pool_id, 1, "", {"from": operator}) + + with self.assertRaises(VirtualMachineError): + self.terminus.mint(user.address, pool_id, 1, "", {"from": operator}) + + controller_balance_1 = self.terminus.balance_of(controller.address, pool_id) + operator_balance_1 = self.terminus.balance_of(operator.address, pool_id) + user_balance_1 = self.terminus.balance_of(user.address, pool_id) + + self.assertEqual(controller_balance_1, controller_balance_0) + self.assertEqual(operator_balance_1, operator_balance_0) + self.assertEqual(user_balance_1, user_balance_0) + + with self.assertRaises(VirtualMachineError): + self.terminus.burn(controller.address, pool_id, 1, {"from": operator}) + + self.terminus.burn(operator.address, pool_id, 1, {"from": operator}) + + with self.assertRaises(VirtualMachineError): + self.terminus.burn(user.address, pool_id, 1, {"from": operator}) + + controller_balance_2 = self.terminus.balance_of(controller.address, pool_id) + operator_balance_2 = self.terminus.balance_of(operator.address, pool_id) + user_balance_2 = self.terminus.balance_of(user.address, pool_id) + + self.assertEqual(controller_balance_2, controller_balance_1) + self.assertEqual(operator_balance_2, operator_balance_1 - 1) + self.assertEqual(user_balance_2, user_balance_1) + + with self.assertRaises(VirtualMachineError): + self.terminus.approve_for_pool(pool_id, operator, {"from": operator}) + + self.terminus.approve_for_pool(pool_id, operator, {"from": accounts[1]}) + + self.assertTrue(self.terminus.is_approved_for_pool(pool_id, operator.address)) + + self.terminus.mint(controller.address, pool_id, 1, "", {"from": operator}) + self.terminus.mint(operator.address, pool_id, 1, "", {"from": operator}) + self.terminus.mint(user.address, pool_id, 1, "", {"from": operator}) + + controller_balance_3 = self.terminus.balance_of(controller.address, pool_id) + operator_balance_3 = self.terminus.balance_of(operator.address, pool_id) + user_balance_3 = self.terminus.balance_of(user.address, pool_id) + + self.assertEqual(controller_balance_3, controller_balance_2 + 1) + self.assertEqual(operator_balance_3, operator_balance_2 + 1) + self.assertEqual(user_balance_3, user_balance_2 + 1) + + self.terminus.burn(controller.address, pool_id, 1, {"from": operator}) + self.terminus.burn(operator.address, pool_id, 1, {"from": operator}) + self.terminus.burn(user.address, pool_id, 1, {"from": operator}) + + controller_balance_4 = self.terminus.balance_of(controller.address, pool_id) + operator_balance_4 = self.terminus.balance_of(operator.address, pool_id) + user_balance_4 = self.terminus.balance_of(user.address, pool_id) + + self.assertEqual(controller_balance_4, controller_balance_3 - 1) + self.assertEqual(operator_balance_4, operator_balance_3 - 1) + self.assertEqual(user_balance_4, user_balance_3 - 1) + + with self.assertRaises(VirtualMachineError): + self.terminus.unapprove_for_pool(pool_id, operator, {"from": operator}) + + self.assertTrue(self.terminus.is_approved_for_pool(pool_id, operator.address)) + + self.terminus.unapprove_for_pool(pool_id, operator, {"from": controller}) + + self.assertFalse(self.terminus.is_approved_for_pool(pool_id, operator.address)) + + with self.assertRaises(VirtualMachineError): + self.terminus.mint(controller.address, pool_id, 1, "", {"from": operator}) + + with self.assertRaises(VirtualMachineError): + self.terminus.mint(operator.address, pool_id, 1, "", {"from": operator}) + + with self.assertRaises(VirtualMachineError): + self.terminus.mint(user.address, pool_id, 1, "", {"from": operator}) + + controller_balance_5 = self.terminus.balance_of(controller.address, pool_id) + operator_balance_5 = self.terminus.balance_of(operator.address, pool_id) + user_balance_5 = self.terminus.balance_of(user.address, pool_id) + + self.assertEqual(controller_balance_5, controller_balance_4) + self.assertEqual(operator_balance_5, operator_balance_4) + self.assertEqual(user_balance_5, user_balance_4) + + with self.assertRaises(VirtualMachineError): + self.terminus.burn(controller.address, pool_id, 1, {"from": operator}) + + self.terminus.burn(operator.address, pool_id, 1, {"from": operator}) + + with self.assertRaises(VirtualMachineError): + self.terminus.burn(user.address, pool_id, 1, {"from": operator}) + + controller_balance_6 = self.terminus.balance_of(controller.address, pool_id) + operator_balance_6 = self.terminus.balance_of(operator.address, pool_id) + user_balance_6 = self.terminus.balance_of(user.address, pool_id) + + self.assertEqual(controller_balance_6, controller_balance_5) + self.assertEqual(operator_balance_6, operator_balance_5 - 1) + self.assertEqual(user_balance_6, user_balance_5) + + +class TestPoolCreation(TestPoolOperations): + def setUp(self): + self.terminus.create_pool_v1(10, True, False, {"from": accounts[1]}) + + def test_nontransferable_pool(self): + self.terminus.create_pool_v1(10, False, False, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + initial_receiver_balance = self.terminus.balance_of( + accounts[3].address, pool_id + ) + + with self.assertRaises(Exception): + self.terminus.safe_transfer_from( + accounts[2].address, + accounts[3].address, + pool_id, + 1, + b"", + {"from": accounts[2]}, + ) + + final_sender_balance = self.terminus.balance_of(accounts[2].address, pool_id) + final_receiver_balance = self.terminus.balance_of(accounts[3].address, pool_id) + + self.assertEqual(final_sender_balance, initial_sender_balance) + self.assertEqual(final_receiver_balance, initial_receiver_balance) + + def test_pool_state_view_methods(self): + nontransferable_nonburnable_pool_uri = "https://example.com/ff.json" + self.terminus.create_pool_v2( + 10, + False, + False, + nontransferable_nonburnable_pool_uri, + {"from": accounts[1]}, + ) + nontransferable_nonburnable_pool_id = self.terminus.total_pools() + self.assertFalse( + self.terminus.pool_is_transferable(nontransferable_nonburnable_pool_id) + ) + self.assertFalse( + self.terminus.pool_is_burnable(nontransferable_nonburnable_pool_id) + ) + self.assertEqual( + self.terminus.uri(nontransferable_nonburnable_pool_id), + nontransferable_nonburnable_pool_uri, + ) + + transferable_nonburnable_pool_uri = "https://example.com/tf.json" + self.terminus.create_pool_v2( + 10, True, False, transferable_nonburnable_pool_uri, {"from": accounts[1]} + ) + transferable_nonburnable_pool_id = self.terminus.total_pools() + self.assertTrue( + self.terminus.pool_is_transferable(transferable_nonburnable_pool_id) + ) + self.assertFalse( + self.terminus.pool_is_burnable(transferable_nonburnable_pool_id) + ) + self.assertEqual( + self.terminus.uri(transferable_nonburnable_pool_id), + transferable_nonburnable_pool_uri, + ) + + transferable_burnable_pool_uri = "https://example.com/tt.json" + self.terminus.create_pool_v2( + 10, True, True, transferable_burnable_pool_uri, {"from": accounts[1]} + ) + transferable_burnable_pool_id = self.terminus.total_pools() + self.assertTrue( + self.terminus.pool_is_transferable(transferable_burnable_pool_id) + ) + self.assertTrue(self.terminus.pool_is_burnable(transferable_burnable_pool_id)) + self.assertEqual( + self.terminus.uri(transferable_burnable_pool_id), + transferable_burnable_pool_uri, + ) + + nontransferable_burnable_pool_uri = "https://example.com/ft.json" + self.terminus.create_pool_v2( + 10, False, True, nontransferable_burnable_pool_uri, {"from": accounts[1]} + ) + nontransferable_burnable_pool_id = self.terminus.total_pools() + self.assertFalse( + self.terminus.pool_is_transferable(nontransferable_burnable_pool_id) + ) + self.assertTrue( + self.terminus.pool_is_burnable(nontransferable_burnable_pool_id) + ) + self.assertEqual( + self.terminus.uri(nontransferable_burnable_pool_id), + nontransferable_burnable_pool_uri, + ) + + def test_pool_state_setters(self): + self.terminus.create_pool_v1(10, False, False, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + self.assertEqual( + self.terminus.terminus_pool_controller(pool_id), accounts[1].address + ) + + self.assertFalse(self.terminus.pool_is_transferable(pool_id)) + self.assertFalse(self.terminus.pool_is_burnable(pool_id)) + + self.terminus.set_pool_transferable(pool_id, True, {"from": accounts[1]}) + self.assertTrue(self.terminus.pool_is_transferable(pool_id)) + self.assertFalse(self.terminus.pool_is_burnable(pool_id)) + + self.terminus.set_pool_burnable(pool_id, True, {"from": accounts[1]}) + self.assertTrue(self.terminus.pool_is_transferable(pool_id)) + self.assertTrue(self.terminus.pool_is_burnable(pool_id)) + + self.terminus.set_pool_transferable(pool_id, False, {"from": accounts[1]}) + self.assertFalse(self.terminus.pool_is_transferable(pool_id)) + self.assertTrue(self.terminus.pool_is_burnable(pool_id)) + + self.terminus.set_pool_burnable(pool_id, False, {"from": accounts[1]}) + self.assertFalse(self.terminus.pool_is_transferable(pool_id)) + self.assertFalse(self.terminus.pool_is_burnable(pool_id)) + + def test_pool_state_setters_do_not_allow_noncontroller_to_set_parameters(self): + self.terminus.create_pool_v1(10, False, False, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + self.assertEqual( + self.terminus.terminus_pool_controller(pool_id), accounts[1].address + ) + + self.assertFalse(self.terminus.pool_is_transferable(pool_id)) + self.assertFalse(self.terminus.pool_is_burnable(pool_id)) + + with self.assertRaises(VirtualMachineError): + self.terminus.set_pool_transferable(pool_id, True, {"from": accounts[2]}) + + with self.assertRaises(VirtualMachineError): + self.terminus.set_pool_burnable(pool_id, True, {"from": accounts[2]}) + + self.assertFalse(self.terminus.pool_is_transferable(pool_id)) + self.assertFalse(self.terminus.pool_is_burnable(pool_id)) + + def test_burnable_pool_burn_as_token_owner(self): + self.terminus.create_pool_v1(10, True, True, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.terminus.burn(accounts[2].address, pool_id, 1, {"from": accounts[2]}) + + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + final_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply - 1) + self.assertEqual(final_owner_balance, initial_owner_balance - 1) + + def test_burnable_pool_burn_as_pool_controller(self): + self.terminus.create_pool_v1(10, True, True, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.terminus.burn(accounts[2].address, pool_id, 1, {"from": accounts[1]}) + + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + final_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply - 1) + self.assertEqual(final_owner_balance, initial_owner_balance - 1) + + def test_burnable_pool_burn_as_authorized_third_party(self): + self.terminus.create_pool_v1(10, True, True, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.terminus.approve_for_pool( + pool_id, accounts[3].address, {"from": accounts[1]} + ) + self.terminus.burn(accounts[2].address, pool_id, 1, {"from": accounts[3]}) + + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + final_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply - 1) + self.assertEqual(final_owner_balance, initial_owner_balance - 1) + + def test_burnable_pool_burn_as_unauthorized_third_party(self): + self.terminus.create_pool_v1(10, True, True, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + with self.assertRaises(Exception): + self.terminus.burn(accounts[2].address, pool_id, 1, {"from": accounts[3]}) + + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + final_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply) + self.assertEqual(final_owner_balance, initial_owner_balance) + + def test_nontransferable_pool_safe_transfer_from(self): + self.terminus.create_pool_v1(10, False, False, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + with self.assertRaises(Exception): + self.terminus.safe_transfer_from( + accounts[2].address, + accounts[3].address, + pool_id, + 1, + b"", + {"from": accounts[2]}, + ) + + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + final_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply) + self.assertEqual(final_owner_balance, initial_owner_balance) + + def test_nontransferable_pool_safe_batch_transfer_from(self): + self.terminus.create_pool_v1(10, False, False, {"from": accounts[1]}) + pool_id = self.terminus.total_pools() + self.terminus.mint(accounts[2], pool_id, 1, b"", {"from": accounts[1]}) + + initial_pool_supply = self.terminus.terminus_pool_supply(pool_id) + initial_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + with self.assertRaises(Exception): + self.terminus.safe_batch_transfer_from( + accounts[2].address, + accounts[3].address, + [pool_id], + [1], + b"", + {"from": accounts[2]}, + ) + + final_pool_supply = self.terminus.terminus_pool_supply(pool_id) + final_owner_balance = self.terminus.balance_of(accounts[2].address, pool_id) + self.assertEqual(final_pool_supply, initial_pool_supply) + self.assertEqual(final_owner_balance, initial_owner_balance) + + +if __name__ == "__main__": + unittest.main() From ef54bea6034cd907ae64d98c15cf499a65494eea Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Sun, 20 Aug 2023 22:01:45 -0700 Subject: [PATCH 10/12] Added Terminus tests to CI/CD --- .github/workflows/terminus.yml | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/terminus.yml diff --git a/.github/workflows/terminus.yml b/.github/workflows/terminus.yml new file mode 100644 index 00000000..27659a86 --- /dev/null +++ b/.github/workflows/terminus.yml @@ -0,0 +1,41 @@ +name: Inventory system tests + +on: + pull_request: + paths: + - "contracts/terminus/**" + - "contracts/mock/**" + - "cli/web3cli/test_terminus.py" + - "cli/web3cli/TerminusFacet.py" + - ".github/workflows/terminus.yml" + branches: + - main +jobs: + build: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: "16" + - uses: actions/setup-python@v2 + with: + python-version: "3.9" + - name: Install ganache + run: npm install -g ganache-cli + - name: Upgrade pip + env: + BROWNIE_LIB: 1 + run: pip install -U pip + - name: Install additional dev dependencies + run: | + pip install black moonworm + - name: Install dependencies for CLI + working-directory: cli/ + env: + BROWNIE_LIB: 1 + run: | + pip install -e . + - name: Run tests + working-directory: cli/ + run: bash test.sh web3cli.test_terminus From e2d73d38e129ffc95754f5618dae87ffc41d9e68 Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Sun, 20 Aug 2023 22:02:47 -0700 Subject: [PATCH 11/12] Renamed GitHub Action for Terminus tests. --- .github/workflows/terminus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/terminus.yml b/.github/workflows/terminus.yml index 27659a86..a9e648bc 100644 --- a/.github/workflows/terminus.yml +++ b/.github/workflows/terminus.yml @@ -1,4 +1,4 @@ -name: Inventory system tests +name: Terminus protocol tests on: pull_request: From 08ff1881a3b70a155929c571f7968ff252cc3772 Mon Sep 17 00:00:00 2001 From: Neeraj Kashyap Date: Sun, 20 Aug 2023 22:05:22 -0700 Subject: [PATCH 12/12] Regenerated ABIs in `abi/` directory --- abi/ERC1155WithTerminusStorage.json | 379 ++++++++++ abi/GOFPFacet.json | 458 +++++++++++- abi/GOFPPredicates.json | 46 ++ abi/IGOFP.json | 1005 +++++++++++++++++++++++++++ abi/LibTerminus.json | 46 ++ abi/MockTerminus.json | 52 ++ abi/TerminusFacet.json | 902 ++++++++++++++++++++++++ abi/TerminusInitializer.json | 9 + abi/TerminusPermissions.json | 1 + 9 files changed, 2897 insertions(+), 1 deletion(-) create mode 100644 abi/ERC1155WithTerminusStorage.json create mode 100644 abi/GOFPPredicates.json create mode 100644 abi/IGOFP.json create mode 100644 abi/LibTerminus.json create mode 100644 abi/TerminusFacet.json create mode 100644 abi/TerminusInitializer.json create mode 100644 abi/TerminusPermissions.json diff --git a/abi/ERC1155WithTerminusStorage.json b/abi/ERC1155WithTerminusStorage.json new file mode 100644 index 00000000..b1db97a3 --- /dev/null +++ b/abi/ERC1155WithTerminusStorage.json @@ -0,0 +1,379 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + } + ], + "name": "TransferBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "TransferSingle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "value", + "type": "string" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "URI", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "approveForPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + } + ], + "name": "balanceOfBatch", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForPool", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeBatchTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "unapproveForPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + } + ], + "name": "uri", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/GOFPFacet.json b/abi/GOFPFacet.json index 19433558..a737ce0b 100644 --- a/abi/GOFPFacet.json +++ b/abi/GOFPFacet.json @@ -1,4 +1,47 @@ [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "path", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "predicateAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes4", + "name": "functionSelector", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "initialArguments", + "type": "bytes" + } + ], + "name": "PathChoicePredicateSet", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -55,6 +98,49 @@ "name": "PathRegistered", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "path", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "terminusPoolId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rewardAmount", + "type": "uint256" + } + ], + "name": "PathRewardChanged", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -198,6 +284,37 @@ "name": "StageRewardChanged", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "predicateAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes4", + "name": "functionSelector", + "type": "bytes4" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "initialArguments", + "type": "bytes" + } + ], + "name": "StakingPredicateSet", + "type": "event" + }, { "inputs": [], "name": "adminTerminusInfo", @@ -216,6 +333,81 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stageNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pathNumber", + "type": "uint256" + } + ], + "internalType": "struct PathDetails", + "name": "path", + "type": "tuple" + }, + { + "internalType": "address", + "name": "player", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "callPathChoicePredicate", + "outputs": [ + { + "internalType": "bool", + "name": "valid", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "player", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "callSessionStakingPredicate", + "outputs": [ + { + "internalType": "bool", + "name": "valid", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -354,6 +546,105 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stageNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pathNumber", + "type": "uint256" + } + ], + "internalType": "struct PathDetails", + "name": "path", + "type": "tuple" + } + ], + "name": "getPathChoicePredicate", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "predicateAddress", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "functionSelector", + "type": "bytes4" + }, + { + "internalType": "bytes", + "name": "initialArguments", + "type": "bytes" + } + ], + "internalType": "struct Predicate", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "path", + "type": "uint256" + } + ], + "name": "getPathReward", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "terminusPoolId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardAmount", + "type": "uint256" + } + ], + "internalType": "struct Reward", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -415,6 +706,42 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + } + ], + "name": "getSessionStakingPredicate", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "predicateAddress", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "functionSelector", + "type": "bytes4" + }, + { + "internalType": "bytes", + "name": "initialArguments", + "type": "bytes" + } + ], + "internalType": "struct Predicate", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -472,7 +799,7 @@ "type": "uint256" } ], - "internalType": "struct StageReward", + "internalType": "struct Reward", "name": "", "type": "tuple" } @@ -509,6 +836,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "gofpVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + }, + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, { "inputs": [ { @@ -704,6 +1049,89 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stageNumber", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pathNumber", + "type": "uint256" + } + ], + "internalType": "struct PathDetails", + "name": "path", + "type": "tuple" + }, + { + "internalType": "bytes4", + "name": "functionSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "predicateAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initialArguments", + "type": "bytes" + } + ], + "name": "setPathChoicePredicate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "stages", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "paths", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "terminusAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "terminusPoolIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "rewardAmounts", + "type": "uint256[]" + } + ], + "name": "setPathRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -740,6 +1168,34 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "bytes4", + "name": "functionSelector", + "type": "bytes4" + }, + { + "internalType": "address", + "name": "predicateAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "initialArguments", + "type": "bytes" + } + ], + "name": "setSessionStakingPredicate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/GOFPPredicates.json b/abi/GOFPPredicates.json new file mode 100644 index 00000000..d6bfb7e4 --- /dev/null +++ b/abi/GOFPPredicates.json @@ -0,0 +1,46 @@ +[ + { + "inputs": [ + { + "internalType": "uint256", + "name": "maxStakable", + "type": "uint256" + }, + { + "internalType": "address", + "name": "gofpAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "player", + "type": "address" + }, + { + "internalType": "address", + "name": "nftAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "doesNotExceedMaxTokensInSession", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/IGOFP.json b/abi/IGOFP.json new file mode 100644 index 00000000..8682bb12 --- /dev/null +++ b/abi/IGOFP.json @@ -0,0 +1,1005 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "path", + "type": "uint256" + } + ], + "name": "PathChosen", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "path", + "type": "uint256" + } + ], + "name": "PathRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "path", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "terminusPoolId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rewardAmount", + "type": "uint256" + } + ], + "name": "PathRewardChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isActive", + "type": "bool" + } + ], + "name": "SessionActivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isChoosingActive", + "type": "bool" + } + ], + "name": "SessionChoosingActivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "playerTokenAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "paymentTokenAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "paymentAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "uri", + "type": "string" + }, + { + "indexed": false, + "internalType": "bool", + "name": "active", + "type": "bool" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isForgiving", + "type": "bool" + } + ], + "name": "SessionCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "SessionUriChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "terminusPoolId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rewardAmount", + "type": "uint256" + } + ], + "name": "StageRewardChanged", + "type": "event" + }, + { + "inputs": [], + "name": "adminTerminusInfo", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "paths", + "type": "uint256[]" + } + ], + "name": "chooseCurrentStagePaths", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "playerTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "paymentTokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "paymentAmount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + }, + { + "internalType": "uint256[]", + "name": "stages", + "type": "uint256[]" + }, + { + "internalType": "bool", + "name": "isForgiving", + "type": "bool" + } + ], + "name": "createSession", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stage", + "type": "uint256" + } + ], + "name": "getCorrectPathForStage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + } + ], + "name": "getCurrentStage", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stage", + "type": "uint256" + } + ], + "name": "getPathChoice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "path", + "type": "uint256" + } + ], + "name": "getPathReward", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "terminusPoolId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardAmount", + "type": "uint256" + } + ], + "internalType": "struct IGOFP.Compound0", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + } + ], + "name": "getSession", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "playerTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "paymentTokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "paymentAmount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isChoosingActive", + "type": "bool" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + }, + { + "internalType": "uint256[]", + "name": "stages", + "type": "uint256[]" + }, + { + "internalType": "bool", + "name": "isForgiving", + "type": "bool" + } + ], + "internalType": "struct IGOFP.Compound1", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getSessionTokenStakeGuard", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stage", + "type": "uint256" + } + ], + "name": "getStageReward", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "terminusAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "terminusPoolId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardAmount", + "type": "uint256" + } + ], + "internalType": "struct IGOFP.Compound2", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "nftAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getStakedTokenInfo", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "adminTerminusAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "adminTerminusPoolID", + "type": "uint256" + } + ], + "name": "init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "numSessions", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "staker", + "type": "address" + } + ], + "name": "numTokensStakedIntoSession", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC1155BatchReceived", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC1155Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "path", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "setIsChoosingActive", + "type": "bool" + } + ], + "name": "setCorrectPathForStage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "stages", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "paths", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "terminusAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "terminusPoolIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "rewardAmounts", + "type": "uint256[]" + } + ], + "name": "setPathRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + } + ], + "name": "setSessionActive", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "isChoosingActive", + "type": "bool" + } + ], + "name": "setSessionChoosingActive", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "setSessionUri", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "stages", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "terminusAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "terminusPoolIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "rewardAmounts", + "type": "uint256[]" + } + ], + "name": "setStageRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + } + ], + "name": "stakeTokensIntoSession", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "staker", + "type": "address" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "tokenOfStakerInSessionByIndex", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "sessionId", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "tokenIds", + "type": "uint256[]" + } + ], + "name": "unstakeTokensFromSession", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/LibTerminus.json b/abi/LibTerminus.json new file mode 100644 index 00000000..a25a2753 --- /dev/null +++ b/abi/LibTerminus.json @@ -0,0 +1,46 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousController", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newController", + "type": "address" + } + ], + "name": "ControlTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "previousController", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newController", + "type": "address" + } + ], + "name": "PoolControlTransferred", + "type": "event" + } +] \ No newline at end of file diff --git a/abi/MockTerminus.json b/abi/MockTerminus.json index cb1f6654..e1639763 100644 --- a/abi/MockTerminus.json +++ b/abi/MockTerminus.json @@ -290,6 +290,40 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_capacity", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_transferable", + "type": "bool" + }, + { + "internalType": "bool", + "name": "_burnable", + "type": "bool" + }, + { + "internalType": "string", + "name": "poolURI", + "type": "string" + } + ], + "name": "createPoolV2", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -810,6 +844,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "unapproveForPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { diff --git a/abi/TerminusFacet.json b/abi/TerminusFacet.json new file mode 100644 index 00000000..e1639763 --- /dev/null +++ b/abi/TerminusFacet.json @@ -0,0 +1,902 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "toAddresses", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "name": "PoolMintBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + } + ], + "name": "TransferBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "TransferSingle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "value", + "type": "string" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "URI", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "approveForPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + } + ], + "name": "balanceOfBatch", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "contractURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_capacity", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_transferable", + "type": "bool" + }, + { + "internalType": "bool", + "name": "_burnable", + "type": "bool" + } + ], + "name": "createPoolV1", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_capacity", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_transferable", + "type": "bool" + }, + { + "internalType": "bool", + "name": "_burnable", + "type": "bool" + }, + { + "internalType": "string", + "name": "poolURI", + "type": "string" + } + ], + "name": "createPoolV2", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_capacity", + "type": "uint256" + } + ], + "name": "createSimplePool", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForPool", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "poolIDs", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "mintBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paymentToken", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "poolBasePrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + } + ], + "name": "poolIsBurnable", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + } + ], + "name": "poolIsTransferable", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "toAddresses", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "name": "poolMintBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeBatchTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_contractURI", + "type": "string" + } + ], + "name": "setContractURI", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newController", + "type": "address" + } + ], + "name": "setController", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newPaymentToken", + "type": "address" + } + ], + "name": "setPaymentToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newBasePrice", + "type": "uint256" + } + ], + "name": "setPoolBasePrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "burnable", + "type": "bool" + } + ], + "name": "setPoolBurnable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "address", + "name": "newController", + "type": "address" + } + ], + "name": "setPoolController", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "transferable", + "type": "bool" + } + ], + "name": "setPoolTransferable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "string", + "name": "poolURI", + "type": "string" + } + ], + "name": "setURI", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "terminusController", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + } + ], + "name": "terminusPoolCapacity", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + } + ], + "name": "terminusPoolController", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + } + ], + "name": "terminusPoolSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalPools", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "unapproveForPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "poolID", + "type": "uint256" + } + ], + "name": "uri", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "toAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdrawPayments", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/TerminusInitializer.json b/abi/TerminusInitializer.json new file mode 100644 index 00000000..1a4cdbe8 --- /dev/null +++ b/abi/TerminusInitializer.json @@ -0,0 +1,9 @@ +[ + { + "inputs": [], + "name": "init", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/abi/TerminusPermissions.json b/abi/TerminusPermissions.json new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/abi/TerminusPermissions.json @@ -0,0 +1 @@ +[] \ No newline at end of file