From 6225e9e4705e48e7f9bde73620105356a4d7adb8 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Mon, 9 May 2022 17:51:55 -0700 Subject: [PATCH 01/16] leanify thirdwebContract --- contracts/ByocFactory.sol | 14 ++++++------ contracts/ThirdwebContract.sol | 31 ++++----------------------- contracts/interfaces/IByocFactory.sol | 8 +++---- 3 files changed, 15 insertions(+), 38 deletions(-) diff --git a/contracts/ByocFactory.sol b/contracts/ByocFactory.sol index e20e00f5e..e782eae12 100644 --- a/contracts/ByocFactory.sol +++ b/contracts/ByocFactory.sol @@ -51,19 +51,19 @@ contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable, T bytes memory _constructorArgs, bytes32 _salt, uint256 _value, - ThirdwebContract.ThirdwebInfo memory _thirdwebInfo + string memory publishMetadataUri ) external onlyUnpausedOrAdmin returns (address deployedAddress) { - require(bytes(_thirdwebInfo.publishMetadataUri).length > 0, "No publish metadata"); + require(bytes(publishMetadataUri).length > 0, "No publish metadata"); bytes memory contractBytecode = abi.encodePacked(_contractBytecode, _constructorArgs); bytes32 salt = _salt == "" ? keccak256(abi.encodePacked(_msgSender(), block.number)) : _salt; deployedAddress = Create2.deploy(_value, salt, contractBytecode); - ThirdwebContract(deployedAddress).setThirdwebInfo(_thirdwebInfo); + ThirdwebContract(deployedAddress).setPublisheMetadataUi(publishMetadataUri); require( keccak256(bytes(ThirdwebContract(deployedAddress).getPublishMetadataUri())) == - keccak256(bytes(_thirdwebInfo.publishMetadataUri)), + keccak256(bytes(publishMetadataUri)), "Not a thirdweb contract" ); @@ -79,15 +79,15 @@ contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable, T bytes memory _initializeData, bytes32 _salt, uint256 _value, - ThirdwebContract.ThirdwebInfo memory _thirdwebInfo + string memory publishMetadataUri ) external onlyUnpausedOrAdmin returns (address deployedAddress) { bytes32 salt = _salt == "" ? keccak256(abi.encodePacked(_msgSender(), block.number)) : _salt; deployedAddress = Clones.cloneDeterministic(_implementation, salt); - ThirdwebContract(deployedAddress).setThirdwebInfo(_thirdwebInfo); + ThirdwebContract(deployedAddress).setPublisheMetadataUi(publishMetadataUri); require( keccak256(bytes(ThirdwebContract(deployedAddress).getPublishMetadataUri())) == - keccak256(bytes(_thirdwebInfo.publishMetadataUri)), + keccak256(bytes(publishMetadataUri)), "Not a thirdweb contract" ); diff --git a/contracts/ThirdwebContract.sol b/contracts/ThirdwebContract.sol index c838ce4aa..499b93de9 100644 --- a/contracts/ThirdwebContract.sol +++ b/contracts/ThirdwebContract.sol @@ -1,16 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; -import "./feature/Ownable.sol"; -import "./feature/ContractMetadata.sol"; - -contract ThirdwebContract is Ownable, ContractMetadata { - struct ThirdwebInfo { - string publishMetadataUri; - string contractURI; - address owner; - } - +contract ThirdwebContract { /// @dev The publish metadata of the contract of which this contract is an instance. string private publishMetadataUri; @@ -19,23 +10,9 @@ contract ThirdwebContract is Ownable, ContractMetadata { return publishMetadataUri; } - /// @dev Initializes the publish metadata and contract metadata at deploy time. - function setThirdwebInfo(ThirdwebInfo memory _thirdwebInfo) external { + /// @dev Initializes the publish metadata and at deploy time. + function setPublisheMetadataUi(string memory uri) external { require(bytes(publishMetadataUri).length == 0, "Published metadata already initialized"); - require(owner == address(0), "Owner already initialized"); - - publishMetadataUri = _thirdwebInfo.publishMetadataUri; - contractURI = _thirdwebInfo.contractURI; - owner = _thirdwebInfo.owner; - } - - /// @dev Returns whether owner can be set - function _canSetOwner() internal virtual override returns (bool) { - return msg.sender == owner; - } - - /// @dev Returns whether contract metadata can be set - function _canSetContractURI() internal virtual override returns (bool) { - return msg.sender == owner; + publishMetadataUri = uri; } } diff --git a/contracts/interfaces/IByocFactory.sol b/contracts/interfaces/IByocFactory.sol index d40e3a969..3027fbe37 100644 --- a/contracts/interfaces/IByocFactory.sol +++ b/contracts/interfaces/IByocFactory.sol @@ -18,7 +18,7 @@ interface IByocFactory { * @param constructorArgs The encoded constructor args to deploy the contract with. * @param salt The salt to use in the CREATE2 contract deployment. * @param value The native token value to pass to the contract on deployment. - * @param thirdwebInfo The publish metadata URI and contract URI for the contract to deploy. + * @param publishMetadataUri The publish metadata URI for the contract to deploy. * * @return deployedAddress The address of the contract deployed. */ @@ -28,7 +28,7 @@ interface IByocFactory { bytes memory constructorArgs, bytes32 salt, uint256 value, - ThirdwebContract.ThirdwebInfo memory thirdwebInfo + string memory publishMetadataUri ) external returns (address deployedAddress); /** @@ -39,7 +39,7 @@ interface IByocFactory { * @param initializeData The encoded function call to initialize the contract with. * @param salt The salt to use in the CREATE2 contract deployment. * @param value The native token value to pass to the contract on deployment. - * @param thirdwebInfo The publish metadata URI and contract URI for the contract to deploy. + * @param publishMetadataUri The publish metadata URI and for the contract to deploy. * * @return deployedAddress The address of the contract deployed. */ @@ -49,6 +49,6 @@ interface IByocFactory { bytes memory initializeData, bytes32 salt, uint256 value, - ThirdwebContract.ThirdwebInfo memory thirdwebInfo + string memory publishMetadataUri ) external returns (address deployedAddress); } From 6af54ba168e4a2af3982ba3b38312e922df03160 Mon Sep 17 00:00:00 2001 From: Krishang Nadgauda Date: Tue, 10 May 2022 17:50:58 -0400 Subject: [PATCH 02/16] add _thirdwebMsgSender() --- contracts/ThirdwebContract.sol | 19 +++++++ docs/ByocFactory.md | 99 +++------------------------------- docs/IByocFactory.md | 8 +-- docs/ThirdwebContract.md | 94 ++------------------------------ 4 files changed, 35 insertions(+), 185 deletions(-) diff --git a/contracts/ThirdwebContract.sol b/contracts/ThirdwebContract.sol index 499b93de9..30c651870 100644 --- a/contracts/ThirdwebContract.sol +++ b/contracts/ThirdwebContract.sol @@ -5,6 +5,13 @@ contract ThirdwebContract { /// @dev The publish metadata of the contract of which this contract is an instance. string private publishMetadataUri; + /// @dev The address of the thirdweb factory. + address private immutable factory; + + constructor() { + factory = msg.sender; + } + /// @dev Returns the publish metadata for this contract. function getPublishMetadataUri() external view returns (string memory) { return publishMetadataUri; @@ -15,4 +22,16 @@ contract ThirdwebContract { require(bytes(publishMetadataUri).length == 0, "Published metadata already initialized"); publishMetadataUri = uri; } + + /// @dev Returns msg.sender, if caller is not thirdweb factory. Returns the intended msg.sender if caller is factory. + function _thirdwebMsgSender() internal view returns (address sender) { + if (msg.sender == factory) { + // The assembly code is more direct than the Solidity version using `abi.decode`. + assembly { + sender := shr(96, calldataload(sub(calldatasize(), 20))) + } + } else { + sender = msg.sender; + } + } } diff --git a/docs/ByocFactory.md b/docs/ByocFactory.md index 8aabc371a..f4f9af363 100644 --- a/docs/ByocFactory.md +++ b/docs/ByocFactory.md @@ -27,27 +27,10 @@ function DEFAULT_ADMIN_ROLE() external view returns (bytes32) |---|---|---| | _0 | bytes32 | undefined -### contractURI - -```solidity -function contractURI() external view returns (string) -``` - - - - - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | string | undefined - ### deployInstance ```solidity -function deployInstance(address _publisher, bytes _contractBytecode, bytes _constructorArgs, bytes32 _salt, uint256 _value, ThirdwebContract.ThirdwebInfo _thirdwebInfo) external nonpayable returns (address deployedAddress) +function deployInstance(address _publisher, bytes _contractBytecode, bytes _constructorArgs, bytes32 _salt, uint256 _value, string publishMetadataUri) external nonpayable returns (address deployedAddress) ``` Deploys an instance of a published contract directly. @@ -63,7 +46,7 @@ Deploys an instance of a published contract directly. | _constructorArgs | bytes | undefined | _salt | bytes32 | undefined | _value | uint256 | undefined -| _thirdwebInfo | ThirdwebContract.ThirdwebInfo | undefined +| publishMetadataUri | string | undefined #### Returns @@ -74,7 +57,7 @@ Deploys an instance of a published contract directly. ### deployInstanceProxy ```solidity -function deployInstanceProxy(address _publisher, address _implementation, bytes _initializeData, bytes32 _salt, uint256 _value, ThirdwebContract.ThirdwebInfo _thirdwebInfo) external nonpayable returns (address deployedAddress) +function deployInstanceProxy(address _publisher, address _implementation, bytes _initializeData, bytes32 _salt, uint256 _value, string publishMetadataUri) external nonpayable returns (address deployedAddress) ``` Deploys a clone pointing to an implementation of a published contract. @@ -90,7 +73,7 @@ Deploys a clone pointing to an implementation of a published contract. | _initializeData | bytes | undefined | _salt | bytes32 | undefined | _value | uint256 | undefined -| _thirdwebInfo | ThirdwebContract.ThirdwebInfo | undefined +| publishMetadataUri | string | undefined #### Returns @@ -261,23 +244,6 @@ function isTrustedForwarder(address forwarder) external view returns (bool) |---|---|---| | _0 | bool | undefined -### owner - -```solidity -function owner() external view returns (address) -``` - - - - - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | address | undefined - ### renounceRole ```solidity @@ -312,38 +278,6 @@ function revokeRole(bytes32 role, address account) external nonpayable | role | bytes32 | undefined | account | address | undefined -### setContractURI - -```solidity -function setContractURI(string _uri) external nonpayable -``` - - - -*Lets a contract admin set the URI for contract-level metadata.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _uri | string | undefined - -### setOwner - -```solidity -function setOwner(address _newOwner) external nonpayable -``` - - - -*Lets a contract admin set a new owner for the contract. The new owner must be a contract admin.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _newOwner | address | undefined - ### setPause ```solidity @@ -360,21 +294,21 @@ function setPause(bool _pause) external nonpayable |---|---|---| | _pause | bool | undefined -### setThirdwebInfo +### setPublisheMetadataUi ```solidity -function setThirdwebInfo(ThirdwebContract.ThirdwebInfo _thirdwebInfo) external nonpayable +function setPublisheMetadataUi(string uri) external nonpayable ``` -*Initializes the publish metadata and contract metadata at deploy time.* +*Initializes the publish metadata and at deploy time.* #### Parameters | Name | Type | Description | |---|---|---| -| _thirdwebInfo | ThirdwebContract.ThirdwebInfo | undefined +| uri | string | undefined ### supportsInterface @@ -420,23 +354,6 @@ event ContractDeployed(address indexed deployer, address indexed publisher, addr | publisher `indexed` | address | undefined | | deployedContract | address | undefined | -### OwnerUpdated - -```solidity -event OwnerUpdated(address prevOwner, address newOwner) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | - ### Paused ```solidity diff --git a/docs/IByocFactory.md b/docs/IByocFactory.md index 27717f672..3a6ee0b17 100644 --- a/docs/IByocFactory.md +++ b/docs/IByocFactory.md @@ -13,7 +13,7 @@ ### deployInstance ```solidity -function deployInstance(address publisher, bytes contractBytecode, bytes constructorArgs, bytes32 salt, uint256 value, ThirdwebContract.ThirdwebInfo thirdwebInfo) external nonpayable returns (address deployedAddress) +function deployInstance(address publisher, bytes contractBytecode, bytes constructorArgs, bytes32 salt, uint256 value, string publishMetadataUri) external nonpayable returns (address deployedAddress) ``` Deploys an instance of a published contract directly. @@ -29,7 +29,7 @@ Deploys an instance of a published contract directly. | constructorArgs | bytes | The encoded constructor args to deploy the contract with. | salt | bytes32 | The salt to use in the CREATE2 contract deployment. | value | uint256 | The native token value to pass to the contract on deployment. -| thirdwebInfo | ThirdwebContract.ThirdwebInfo | The publish metadata URI and contract URI for the contract to deploy. +| publishMetadataUri | string | The publish metadata URI for the contract to deploy. #### Returns @@ -40,7 +40,7 @@ Deploys an instance of a published contract directly. ### deployInstanceProxy ```solidity -function deployInstanceProxy(address publisher, address implementation, bytes initializeData, bytes32 salt, uint256 value, ThirdwebContract.ThirdwebInfo thirdwebInfo) external nonpayable returns (address deployedAddress) +function deployInstanceProxy(address publisher, address implementation, bytes initializeData, bytes32 salt, uint256 value, string publishMetadataUri) external nonpayable returns (address deployedAddress) ``` Deploys a clone pointing to an implementation of a published contract. @@ -56,7 +56,7 @@ Deploys a clone pointing to an implementation of a published contract. | initializeData | bytes | The encoded function call to initialize the contract with. | salt | bytes32 | The salt to use in the CREATE2 contract deployment. | value | uint256 | The native token value to pass to the contract on deployment. -| thirdwebInfo | ThirdwebContract.ThirdwebInfo | The publish metadata URI and contract URI for the contract to deploy. +| publishMetadataUri | string | The publish metadata URI and for the contract to deploy. #### Returns diff --git a/docs/ThirdwebContract.md b/docs/ThirdwebContract.md index 31797fb36..eeae10d91 100644 --- a/docs/ThirdwebContract.md +++ b/docs/ThirdwebContract.md @@ -10,23 +10,6 @@ ## Methods -### contractURI - -```solidity -function contractURI() external view returns (string) -``` - - - - - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | string | undefined - ### getPublishMetadataUri ```solidity @@ -44,91 +27,22 @@ function getPublishMetadataUri() external view returns (string) |---|---|---| | _0 | string | undefined -### owner - -```solidity -function owner() external view returns (address) -``` - - - - - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | address | undefined - -### setContractURI - -```solidity -function setContractURI(string _uri) external nonpayable -``` - - - -*Lets a contract admin set the URI for contract-level metadata.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _uri | string | undefined - -### setOwner - -```solidity -function setOwner(address _newOwner) external nonpayable -``` - - - -*Lets a contract admin set a new owner for the contract. The new owner must be a contract admin.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _newOwner | address | undefined - -### setThirdwebInfo +### setPublisheMetadataUi ```solidity -function setThirdwebInfo(ThirdwebContract.ThirdwebInfo _thirdwebInfo) external nonpayable +function setPublisheMetadataUi(string uri) external nonpayable ``` -*Initializes the publish metadata and contract metadata at deploy time.* +*Initializes the publish metadata and at deploy time.* #### Parameters | Name | Type | Description | |---|---|---| -| _thirdwebInfo | ThirdwebContract.ThirdwebInfo | undefined - - - -## Events - -### OwnerUpdated - -```solidity -event OwnerUpdated(address prevOwner, address newOwner) -``` +| uri | string | undefined - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | - - - From 2be8cffc9d2611c0ab9efa024503031f2f890642 Mon Sep 17 00:00:00 2001 From: Krishang Nadgauda Date: Tue, 10 May 2022 20:38:40 -0400 Subject: [PATCH 03/16] wip _thirdwebMsgSender callback solution --- contracts/ByocFactory.sol | 12 +- contracts/ThirdwebContract.sol | 15 +- docs/ByocFactory.md | 24 +- docs/IDeployer.md | 32 + docs/ITempMultiwrap.md | 97 --- docs/TempMultiwrap.md | 1102 -------------------------------- docs/console.md | 12 + 7 files changed, 69 insertions(+), 1225 deletions(-) create mode 100644 docs/IDeployer.md delete mode 100644 docs/ITempMultiwrap.md delete mode 100644 docs/TempMultiwrap.md create mode 100644 docs/console.md diff --git a/contracts/ByocFactory.sol b/contracts/ByocFactory.sol index e782eae12..859dbfcca 100644 --- a/contracts/ByocFactory.sol +++ b/contracts/ByocFactory.sol @@ -13,7 +13,9 @@ import { IByocFactory } from "./interfaces/IByocFactory.sol"; import { TWRegistry } from "./TWRegistry.sol"; import "./ThirdwebContract.sol"; -contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable, ThirdwebContract { +import "hardhat/console.sol"; + +contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable { /*/////////////////////////////////////////////////////////////// State variables //////////////////////////////////////////////////////////////*/ @@ -24,6 +26,9 @@ contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable, T /// @dev Whether the registry is paused. bool public isPaused; + /// @dev Empty var used in deployment. + address public deployer; + /*/////////////////////////////////////////////////////////////// Constructor + modifiers //////////////////////////////////////////////////////////////*/ @@ -53,6 +58,9 @@ contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable, T uint256 _value, string memory publishMetadataUri ) external onlyUnpausedOrAdmin returns (address deployedAddress) { + + deployer = _msgSender(); + require(bytes(publishMetadataUri).length > 0, "No publish metadata"); bytes memory contractBytecode = abi.encodePacked(_contractBytecode, _constructorArgs); @@ -69,6 +77,8 @@ contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable, T registry.add(_publisher, deployedAddress); + delete deployer; + emit ContractDeployed(_msgSender(), _publisher, deployedAddress); } diff --git a/contracts/ThirdwebContract.sol b/contracts/ThirdwebContract.sol index 30c651870..193945fc0 100644 --- a/contracts/ThirdwebContract.sol +++ b/contracts/ThirdwebContract.sol @@ -1,15 +1,23 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; +interface IDeployer { + function deployer() external view returns (address); +} + contract ThirdwebContract { /// @dev The publish metadata of the contract of which this contract is an instance. string private publishMetadataUri; /// @dev The address of the thirdweb factory. - address private immutable factory; + address private factory; + + /// @dev Address of the contract deployer. + address private deployer; constructor() { factory = msg.sender; + deployer = IDeployer(msg.sender).deployer(); } /// @dev Returns the publish metadata for this contract. @@ -26,10 +34,7 @@ contract ThirdwebContract { /// @dev Returns msg.sender, if caller is not thirdweb factory. Returns the intended msg.sender if caller is factory. function _thirdwebMsgSender() internal view returns (address sender) { if (msg.sender == factory) { - // The assembly code is more direct than the Solidity version using `abi.decode`. - assembly { - sender := shr(96, calldataload(sub(calldatasize(), 20))) - } + sender = deployer; } else { sender = msg.sender; } diff --git a/docs/ByocFactory.md b/docs/ByocFactory.md index f4f9af363..226f8ad3a 100644 --- a/docs/ByocFactory.md +++ b/docs/ByocFactory.md @@ -81,22 +81,22 @@ Deploys a clone pointing to an implementation of a published contract. |---|---|---| | deployedAddress | address | undefined -### getPublishMetadataUri +### deployer ```solidity -function getPublishMetadataUri() external view returns (string) +function deployer() external view returns (address) ``` -*Returns the publish metadata for this contract.* +*Empty var used in deployment.* #### Returns | Name | Type | Description | |---|---|---| -| _0 | string | undefined +| _0 | address | undefined ### getRoleAdmin @@ -294,22 +294,6 @@ function setPause(bool _pause) external nonpayable |---|---|---| | _pause | bool | undefined -### setPublisheMetadataUi - -```solidity -function setPublisheMetadataUi(string uri) external nonpayable -``` - - - -*Initializes the publish metadata and at deploy time.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| uri | string | undefined - ### supportsInterface ```solidity diff --git a/docs/IDeployer.md b/docs/IDeployer.md new file mode 100644 index 000000000..51f167cdc --- /dev/null +++ b/docs/IDeployer.md @@ -0,0 +1,32 @@ +# IDeployer + + + + + + + + + +## Methods + +### deployer + +```solidity +function deployer() external view returns (address) +``` + + + + + + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | address | undefined + + + + diff --git a/docs/ITempMultiwrap.md b/docs/ITempMultiwrap.md deleted file mode 100644 index 7fdffe898..000000000 --- a/docs/ITempMultiwrap.md +++ /dev/null @@ -1,97 +0,0 @@ -# ITempMultiwrap - - - - - -Thirdweb's Multiwrap contract lets you wrap arbitrary ERC20, ERC721 and ERC1155 tokens you own into a single wrapped token / NFT. A wrapped NFT can be unwrapped i.e. burned in exchange for its underlying contents. - - - -## Methods - -### unwrap - -```solidity -function unwrap(uint256 tokenId, address recipient) external nonpayable -``` - -Unwrap a wrapped NFT to retrieve underlying ERC1155, ERC721, ERC20 tokens. - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| tokenId | uint256 | The token Id of the wrapped NFT to unwrap. -| recipient | address | The recipient of the underlying ERC1155, ERC721, ERC20 tokens of the wrapped NFT. - -### wrap - -```solidity -function wrap(ITokenBundle.Token[] wrappedContents, string uriForWrappedToken, address recipient) external payable returns (uint256 tokenId) -``` - -Wrap multiple ERC1155, ERC721, ERC20 tokens into a single wrapped NFT. - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| wrappedContents | ITokenBundle.Token[] | The tokens to wrap. -| uriForWrappedToken | string | The metadata URI for the wrapped NFT. -| recipient | address | The recipient of the wrapped NFT. - -#### Returns - -| Name | Type | Description | -|---|---|---| -| tokenId | uint256 | undefined - - - -## Events - -### TokensUnwrapped - -```solidity -event TokensUnwrapped(address indexed unwrapper, address indexed recipientOfWrappedContents, uint256 indexed tokenIdOfWrappedToken, ITokenBundle.Token[] wrappedContents) -``` - - - -*Emitted when tokens are unwrapped.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| unwrapper `indexed` | address | undefined | -| recipientOfWrappedContents `indexed` | address | undefined | -| tokenIdOfWrappedToken `indexed` | uint256 | undefined | -| wrappedContents | ITokenBundle.Token[] | undefined | - -### TokensWrapped - -```solidity -event TokensWrapped(address indexed wrapper, address indexed recipientOfWrappedToken, uint256 indexed tokenIdOfWrappedToken, ITokenBundle.Token[] wrappedContents) -``` - - - -*Emitted when tokens are wrapped.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| wrapper `indexed` | address | undefined | -| recipientOfWrappedToken `indexed` | address | undefined | -| tokenIdOfWrappedToken `indexed` | uint256 | undefined | -| wrappedContents | ITokenBundle.Token[] | undefined | - - - diff --git a/docs/TempMultiwrap.md b/docs/TempMultiwrap.md deleted file mode 100644 index 8abf7c184..000000000 --- a/docs/TempMultiwrap.md +++ /dev/null @@ -1,1102 +0,0 @@ -# TempMultiwrap - - - - - - - - - -## Methods - -### DEFAULT_ADMIN_ROLE - -```solidity -function DEFAULT_ADMIN_ROLE() external view returns (bytes32) -``` - - - - - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | bytes32 | undefined - -### approve - -```solidity -function approve(address to, uint256 tokenId) external nonpayable -``` - - - -*See {IERC721-approve}.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| to | address | undefined -| tokenId | uint256 | undefined - -### balanceOf - -```solidity -function balanceOf(address owner) external view returns (uint256) -``` - - - -*See {IERC721-balanceOf}.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| owner | address | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | uint256 | undefined - -### contractType - -```solidity -function contractType() external pure returns (bytes32) -``` - - - -*Returns the type of the contract.* - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | bytes32 | undefined - -### contractURI - -```solidity -function contractURI() external view returns (string) -``` - - - -*Contract level metadata.* - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | string | undefined - -### contractVersion - -```solidity -function contractVersion() external pure returns (uint8) -``` - - - -*Returns the version of the contract.* - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | uint8 | undefined - -### getApproved - -```solidity -function getApproved(uint256 tokenId) external view returns (address) -``` - - - -*See {IERC721-getApproved}.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| tokenId | uint256 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | address | undefined - -### getDefaultRoyaltyInfo - -```solidity -function getDefaultRoyaltyInfo() external view returns (address, uint16) -``` - - - -*Returns the platform fee bps and recipient.* - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | address | undefined -| _1 | uint16 | undefined - -### getRoleAdmin - -```solidity -function getRoleAdmin(bytes32 role) external view returns (bytes32) -``` - - - -*Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| role | bytes32 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | bytes32 | undefined - -### getRoleMember - -```solidity -function getRoleMember(bytes32 role, uint256 index) external view returns (address) -``` - - - -*Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| role | bytes32 | undefined -| index | uint256 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | address | undefined - -### getRoleMemberCount - -```solidity -function getRoleMemberCount(bytes32 role) external view returns (uint256) -``` - - - -*Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| role | bytes32 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | uint256 | undefined - -### getRoyaltyInfoForToken - -```solidity -function getRoyaltyInfoForToken(uint256 _tokenId) external view returns (address, uint16) -``` - - - -*Returns the royalty recipient for a particular token Id.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _tokenId | uint256 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | address | undefined -| _1 | uint16 | undefined - -### getToken - -```solidity -function getToken(uint256 _bundleId, uint256 index) external view returns (struct ITokenBundle.Token) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _bundleId | uint256 | undefined -| index | uint256 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | ITokenBundle.Token | undefined - -### getTokenCount - -```solidity -function getTokenCount(uint256 _bundleId) external view returns (uint256) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _bundleId | uint256 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | uint256 | undefined - -### getUri - -```solidity -function getUri(uint256 _bundleId) external view returns (string) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _bundleId | uint256 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | string | undefined - -### getWrappedContents - -```solidity -function getWrappedContents(uint256 _tokenId) external view returns (struct ITokenBundle.Token[] contents) -``` - - - -*Returns the underlygin contents of a wrapped NFT.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _tokenId | uint256 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| contents | ITokenBundle.Token[] | undefined - -### grantRole - -```solidity -function grantRole(bytes32 role, address account) external nonpayable -``` - - - -*Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| role | bytes32 | undefined -| account | address | undefined - -### hasRole - -```solidity -function hasRole(bytes32 role, address account) external view returns (bool) -``` - - - -*Returns `true` if `account` has been granted `role`.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| role | bytes32 | undefined -| account | address | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | bool | undefined - -### initialize - -```solidity -function initialize(address _defaultAdmin, string _name, string _symbol, string _contractURI, address[] _trustedForwarders, address _royaltyRecipient, uint256 _royaltyBps) external nonpayable -``` - - - -*Initiliazes the contract, like a constructor.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _defaultAdmin | address | undefined -| _name | string | undefined -| _symbol | string | undefined -| _contractURI | string | undefined -| _trustedForwarders | address[] | undefined -| _royaltyRecipient | address | undefined -| _royaltyBps | uint256 | undefined - -### isApprovedForAll - -```solidity -function isApprovedForAll(address owner, address operator) external view returns (bool) -``` - - - -*See {IERC721-isApprovedForAll}.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| owner | address | undefined -| operator | address | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | bool | undefined - -### isTrustedForwarder - -```solidity -function isTrustedForwarder(address forwarder) external view returns (bool) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| forwarder | address | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | bool | undefined - -### multicall - -```solidity -function multicall(bytes[] data) external nonpayable returns (bytes[] results) -``` - - - -*Receives and executes a batch of function calls on this contract.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| data | bytes[] | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| results | bytes[] | undefined - -### name - -```solidity -function name() external view returns (string) -``` - - - -*See {IERC721Metadata-name}.* - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | string | undefined - -### nextTokenIdToMint - -```solidity -function nextTokenIdToMint() external view returns (uint256) -``` - - - -*The next token ID of the NFT to mint.* - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | uint256 | undefined - -### onERC1155BatchReceived - -```solidity -function onERC1155BatchReceived(address, address, uint256[], uint256[], bytes) external nonpayable returns (bytes4) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _0 | address | undefined -| _1 | address | undefined -| _2 | uint256[] | undefined -| _3 | uint256[] | undefined -| _4 | bytes | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | bytes4 | undefined - -### onERC1155Received - -```solidity -function onERC1155Received(address, address, uint256, uint256, bytes) external nonpayable returns (bytes4) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _0 | address | undefined -| _1 | address | undefined -| _2 | uint256 | undefined -| _3 | uint256 | undefined -| _4 | bytes | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | bytes4 | undefined - -### onERC721Received - -```solidity -function onERC721Received(address, address, uint256, bytes) external nonpayable returns (bytes4) -``` - - - -*See {IERC721Receiver-onERC721Received}. Always returns `IERC721Receiver.onERC721Received.selector`.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _0 | address | undefined -| _1 | address | undefined -| _2 | uint256 | undefined -| _3 | bytes | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | bytes4 | undefined - -### owner - -```solidity -function owner() external view returns (address) -``` - - - -*Returns the address of the current owner.* - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | address | undefined - -### ownerOf - -```solidity -function ownerOf(uint256 tokenId) external view returns (address) -``` - - - -*See {IERC721-ownerOf}.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| tokenId | uint256 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | address | undefined - -### renounceRole - -```solidity -function renounceRole(bytes32 role, address account) external nonpayable -``` - - - -*Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| role | bytes32 | undefined -| account | address | undefined - -### revokeRole - -```solidity -function revokeRole(bytes32 role, address account) external nonpayable -``` - - - -*Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| role | bytes32 | undefined -| account | address | undefined - -### royaltyInfo - -```solidity -function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount) -``` - - - -*Returns the royalty recipient and amount, given a tokenId and sale price.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| tokenId | uint256 | undefined -| salePrice | uint256 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| receiver | address | undefined -| royaltyAmount | uint256 | undefined - -### safeTransferFrom - -```solidity -function safeTransferFrom(address from, address to, uint256 tokenId, bytes _data) external nonpayable -``` - - - -*See {IERC721-safeTransferFrom}.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| from | address | undefined -| to | address | undefined -| tokenId | uint256 | undefined -| _data | bytes | undefined - -### setApprovalForAll - -```solidity -function setApprovalForAll(address operator, bool approved) external nonpayable -``` - - - -*See {IERC721-setApprovalForAll}.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| operator | address | undefined -| approved | bool | undefined - -### setContractURI - -```solidity -function setContractURI(string _uri) external nonpayable -``` - - - -*Lets a module admin set the URI for contract-level metadata.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _uri | string | undefined - -### setDefaultRoyaltyInfo - -```solidity -function setDefaultRoyaltyInfo(address _royaltyRecipient, uint256 _royaltyBps) external nonpayable -``` - - - -*Lets a module admin update the royalty bps and recipient.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _royaltyRecipient | address | undefined -| _royaltyBps | uint256 | undefined - -### setOwner - -```solidity -function setOwner(address _newOwner) external nonpayable -``` - - - -*Lets a module admin set a new owner for the contract. The new owner must be a module admin.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _newOwner | address | undefined - -### setRoyaltyInfoForToken - -```solidity -function setRoyaltyInfoForToken(uint256 _tokenId, address _recipient, uint256 _bps) external nonpayable -``` - - - -*Lets a module admin set the royalty recipient for a particular token Id.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _tokenId | uint256 | undefined -| _recipient | address | undefined -| _bps | uint256 | undefined - -### supportsInterface - -```solidity -function supportsInterface(bytes4 interfaceId) external view returns (bool) -``` - - - -*See ERC 165* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| interfaceId | bytes4 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | bool | undefined - -### symbol - -```solidity -function symbol() external view returns (string) -``` - - - -*See {IERC721Metadata-symbol}.* - - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | string | undefined - -### tokenURI - -```solidity -function tokenURI(uint256 _tokenId) external view returns (string) -``` - - - -*Returns the URI for a given tokenId.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _tokenId | uint256 | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| _0 | string | undefined - -### transferFrom - -```solidity -function transferFrom(address from, address to, uint256 tokenId) external nonpayable -``` - - - -*See {IERC721-transferFrom}.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| from | address | undefined -| to | address | undefined -| tokenId | uint256 | undefined - -### unwrap - -```solidity -function unwrap(uint256 _tokenId, address _recipient) external nonpayable -``` - - - -*Unwrap a wrapped NFT to retrieve underlying ERC1155, ERC721, ERC20 tokens.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _tokenId | uint256 | undefined -| _recipient | address | undefined - -### wrap - -```solidity -function wrap(ITokenBundle.Token[] _wrappedContents, string _uriForWrappedToken, address _recipient) external payable returns (uint256 tokenId) -``` - - - -*Wrap multiple ERC1155, ERC721, ERC20 tokens into a single wrapped NFT.* - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| _wrappedContents | ITokenBundle.Token[] | undefined -| _uriForWrappedToken | string | undefined -| _recipient | address | undefined - -#### Returns - -| Name | Type | Description | -|---|---|---| -| tokenId | uint256 | undefined - - - -## Events - -### Approval - -```solidity -event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| owner `indexed` | address | undefined | -| approved `indexed` | address | undefined | -| tokenId `indexed` | uint256 | undefined | - -### ApprovalForAll - -```solidity -event ApprovalForAll(address indexed owner, address indexed operator, bool approved) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| owner `indexed` | address | undefined | -| operator `indexed` | address | undefined | -| approved | bool | undefined | - -### DefaultRoyalty - -```solidity -event DefaultRoyalty(address newRoyaltyRecipient, uint256 newRoyaltyBps) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| newRoyaltyRecipient | address | undefined | -| newRoyaltyBps | uint256 | undefined | - -### OwnerUpdated - -```solidity -event OwnerUpdated(address prevOwner, address newOwner) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| prevOwner | address | undefined | -| newOwner | address | undefined | - -### RoleAdminChanged - -```solidity -event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| role `indexed` | bytes32 | undefined | -| previousAdminRole `indexed` | bytes32 | undefined | -| newAdminRole `indexed` | bytes32 | undefined | - -### RoleGranted - -```solidity -event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| role `indexed` | bytes32 | undefined | -| account `indexed` | address | undefined | -| sender `indexed` | address | undefined | - -### RoleRevoked - -```solidity -event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| role `indexed` | bytes32 | undefined | -| account `indexed` | address | undefined | -| sender `indexed` | address | undefined | - -### RoyaltyForToken - -```solidity -event RoyaltyForToken(uint256 indexed tokenId, address royaltyRecipient, uint256 royaltyBps) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| tokenId `indexed` | uint256 | undefined | -| royaltyRecipient | address | undefined | -| royaltyBps | uint256 | undefined | - -### TokensUnwrapped - -```solidity -event TokensUnwrapped(address indexed unwrapper, address indexed recipientOfWrappedContents, uint256 indexed tokenIdOfWrappedToken, ITokenBundle.Token[] wrappedContents) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| unwrapper `indexed` | address | undefined | -| recipientOfWrappedContents `indexed` | address | undefined | -| tokenIdOfWrappedToken `indexed` | uint256 | undefined | -| wrappedContents | ITokenBundle.Token[] | undefined | - -### TokensWrapped - -```solidity -event TokensWrapped(address indexed wrapper, address indexed recipientOfWrappedToken, uint256 indexed tokenIdOfWrappedToken, ITokenBundle.Token[] wrappedContents) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| wrapper `indexed` | address | undefined | -| recipientOfWrappedToken `indexed` | address | undefined | -| tokenIdOfWrappedToken `indexed` | uint256 | undefined | -| wrappedContents | ITokenBundle.Token[] | undefined | - -### Transfer - -```solidity -event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) -``` - - - - - -#### Parameters - -| Name | Type | Description | -|---|---|---| -| from `indexed` | address | undefined | -| to `indexed` | address | undefined | -| tokenId `indexed` | uint256 | undefined | - - - diff --git a/docs/console.md b/docs/console.md new file mode 100644 index 000000000..8bab67a46 --- /dev/null +++ b/docs/console.md @@ -0,0 +1,12 @@ +# console + + + + + + + + + + + From b9a69f1f6f25046a389e9be21cb33250486603aa Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Tue, 10 May 2022 22:16:59 -0700 Subject: [PATCH 04/16] fix typo - remove one state variable --- contracts/ByocFactory.sol | 5 ++--- contracts/ThirdwebContract.sol | 15 +++------------ docs/ThirdwebContract.md | 4 ++-- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/contracts/ByocFactory.sol b/contracts/ByocFactory.sol index 859dbfcca..59d6ad766 100644 --- a/contracts/ByocFactory.sol +++ b/contracts/ByocFactory.sol @@ -58,7 +58,6 @@ contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable { uint256 _value, string memory publishMetadataUri ) external onlyUnpausedOrAdmin returns (address deployedAddress) { - deployer = _msgSender(); require(bytes(publishMetadataUri).length > 0, "No publish metadata"); @@ -68,7 +67,7 @@ contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable { deployedAddress = Create2.deploy(_value, salt, contractBytecode); - ThirdwebContract(deployedAddress).setPublisheMetadataUi(publishMetadataUri); + ThirdwebContract(deployedAddress).setPublishMetadataUri(publishMetadataUri); require( keccak256(bytes(ThirdwebContract(deployedAddress).getPublishMetadataUri())) == keccak256(bytes(publishMetadataUri)), @@ -94,7 +93,7 @@ contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable { bytes32 salt = _salt == "" ? keccak256(abi.encodePacked(_msgSender(), block.number)) : _salt; deployedAddress = Clones.cloneDeterministic(_implementation, salt); - ThirdwebContract(deployedAddress).setPublisheMetadataUi(publishMetadataUri); + ThirdwebContract(deployedAddress).setPublishMetadataUri(publishMetadataUri); require( keccak256(bytes(ThirdwebContract(deployedAddress).getPublishMetadataUri())) == keccak256(bytes(publishMetadataUri)), diff --git a/contracts/ThirdwebContract.sol b/contracts/ThirdwebContract.sol index 193945fc0..7ff347b18 100644 --- a/contracts/ThirdwebContract.sol +++ b/contracts/ThirdwebContract.sol @@ -8,15 +8,10 @@ interface IDeployer { contract ThirdwebContract { /// @dev The publish metadata of the contract of which this contract is an instance. string private publishMetadataUri; - - /// @dev The address of the thirdweb factory. - address private factory; - /// @dev Address of the contract deployer. address private deployer; constructor() { - factory = msg.sender; deployer = IDeployer(msg.sender).deployer(); } @@ -26,17 +21,13 @@ contract ThirdwebContract { } /// @dev Initializes the publish metadata and at deploy time. - function setPublisheMetadataUi(string memory uri) external { + function setPublishMetadataUri(string memory uri) external { require(bytes(publishMetadataUri).length == 0, "Published metadata already initialized"); publishMetadataUri = uri; } /// @dev Returns msg.sender, if caller is not thirdweb factory. Returns the intended msg.sender if caller is factory. - function _thirdwebMsgSender() internal view returns (address sender) { - if (msg.sender == factory) { - sender = deployer; - } else { - sender = msg.sender; - } + function _contractDeployer() internal view returns (address) { + return deployer; } } diff --git a/docs/ThirdwebContract.md b/docs/ThirdwebContract.md index eeae10d91..aefa9465b 100644 --- a/docs/ThirdwebContract.md +++ b/docs/ThirdwebContract.md @@ -27,10 +27,10 @@ function getPublishMetadataUri() external view returns (string) |---|---|---| | _0 | string | undefined -### setPublisheMetadataUi +### setPublishMetadataUri ```solidity -function setPublisheMetadataUi(string uri) external nonpayable +function setPublishMetadataUri(string uri) external nonpayable ``` From 216379df64aab1ce8ec54b6088e8525c02a24176 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Tue, 10 May 2022 22:44:58 -0700 Subject: [PATCH 05/16] remove console.sol --- contracts/ByocFactory.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/ByocFactory.sol b/contracts/ByocFactory.sol index 59d6ad766..8f0b3ada1 100644 --- a/contracts/ByocFactory.sol +++ b/contracts/ByocFactory.sol @@ -13,8 +13,6 @@ import { IByocFactory } from "./interfaces/IByocFactory.sol"; import { TWRegistry } from "./TWRegistry.sol"; import "./ThirdwebContract.sol"; -import "hardhat/console.sol"; - contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable { /*/////////////////////////////////////////////////////////////// State variables From 7db096793d606e6b7aa94a6b3e9d82540b63caf8 Mon Sep 17 00:00:00 2001 From: Jake Loo <2171134+jakeloo@users.noreply.github.com> Date: Fri, 13 May 2022 09:01:17 +0000 Subject: [PATCH 06/16] Fix salt sniping. Lean ThirdwebContract. Test. --- contracts/ByocFactory.sol | 26 +++++++++++------- contracts/ThirdwebContract.sol | 28 +++++++++++-------- src/test/ThirdwebContract.t.sol | 48 +++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 src/test/ThirdwebContract.t.sol diff --git a/contracts/ByocFactory.sol b/contracts/ByocFactory.sol index 8f0b3ada1..e46646f0f 100644 --- a/contracts/ByocFactory.sol +++ b/contracts/ByocFactory.sol @@ -5,6 +5,7 @@ pragma solidity ^0.8.11; import "@openzeppelin/contracts/utils/Create2.sol"; import "@openzeppelin/contracts/proxy/Clones.sol"; import "@openzeppelin/contracts/utils/Address.sol"; +import "@openzeppelin/contracts/utils/Multicall.sol"; import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; import "@openzeppelin/contracts/metatx/ERC2771Context.sol"; @@ -13,7 +14,7 @@ import { IByocFactory } from "./interfaces/IByocFactory.sol"; import { TWRegistry } from "./TWRegistry.sol"; import "./ThirdwebContract.sol"; -contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable { +contract ByocFactory is IByocFactory, ERC2771Context, Multicall, AccessControlEnumerable { /*/////////////////////////////////////////////////////////////// State variables //////////////////////////////////////////////////////////////*/ @@ -24,8 +25,8 @@ contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable { /// @dev Whether the registry is paused. bool public isPaused; - /// @dev Empty var used in deployment. - address public deployer; + /// @dev contract address deployed through the factory => deployer + mapping(address => address) public getContractDeployer; /*/////////////////////////////////////////////////////////////// Constructor + modifiers @@ -56,12 +57,15 @@ contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable { uint256 _value, string memory publishMetadataUri ) external onlyUnpausedOrAdmin returns (address deployedAddress) { - deployer = _msgSender(); - require(bytes(publishMetadataUri).length > 0, "No publish metadata"); bytes memory contractBytecode = abi.encodePacked(_contractBytecode, _constructorArgs); - bytes32 salt = _salt == "" ? keccak256(abi.encodePacked(_msgSender(), block.number)) : _salt; + bytes32 salt = _salt == "" + ? keccak256(abi.encodePacked(_msgSender(), block.number, keccak256(contractBytecode))) + : keccak256(abi.encodePacked(_msgSender(), _salt)); + + address computedContractAddress = Create2.computeAddress(salt, keccak256(contractBytecode), address(this)); + getContractDeployer[computedContractAddress] = _msgSender(); deployedAddress = Create2.deploy(_value, salt, contractBytecode); @@ -74,8 +78,6 @@ contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable { registry.add(_publisher, deployedAddress); - delete deployer; - emit ContractDeployed(_msgSender(), _publisher, deployedAddress); } @@ -88,7 +90,13 @@ contract ByocFactory is IByocFactory, ERC2771Context, AccessControlEnumerable { uint256 _value, string memory publishMetadataUri ) external onlyUnpausedOrAdmin returns (address deployedAddress) { - bytes32 salt = _salt == "" ? keccak256(abi.encodePacked(_msgSender(), block.number)) : _salt; + bytes32 salt = _salt == "" + ? keccak256(abi.encodePacked(_msgSender(), block.number, _implementation, _initializeData)) + : keccak256(abi.encodePacked(_msgSender(), _salt)); + + address computedContractAddress = Clones.predictDeterministicAddress(_implementation, salt, address(this)); + getContractDeployer[computedContractAddress] = _msgSender(); + deployedAddress = Clones.cloneDeterministic(_implementation, salt); ThirdwebContract(deployedAddress).setPublishMetadataUri(publishMetadataUri); diff --git a/contracts/ThirdwebContract.sol b/contracts/ThirdwebContract.sol index 7ff347b18..e93d9c51b 100644 --- a/contracts/ThirdwebContract.sol +++ b/contracts/ThirdwebContract.sol @@ -1,19 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; -interface IDeployer { - function deployer() external view returns (address); +interface IContractDeployer { + function getContractDeployer(address _contract) external view returns (address); } +error ThirdwebContract_MetadataAlreadyInitialized(); + contract ThirdwebContract { /// @dev The publish metadata of the contract of which this contract is an instance. string private publishMetadataUri; - /// @dev Address of the contract deployer. - address private deployer; - - constructor() { - deployer = IDeployer(msg.sender).deployer(); - } /// @dev Returns the publish metadata for this contract. function getPublishMetadataUri() external view returns (string memory) { @@ -22,12 +18,22 @@ contract ThirdwebContract { /// @dev Initializes the publish metadata and at deploy time. function setPublishMetadataUri(string memory uri) external { - require(bytes(publishMetadataUri).length == 0, "Published metadata already initialized"); + if (bytes(publishMetadataUri).length != 0) { + revert ThirdwebContract_MetadataAlreadyInitialized(); + } publishMetadataUri = uri; } - /// @dev Returns msg.sender, if caller is not thirdweb factory. Returns the intended msg.sender if caller is factory. + /// @dev Enable access to the original contract deployer in the constructor. If this function is called outside of a constructor, it will return address(0) instead. + /// Save 1 storage slot from not storing the factory address and not having to hardcode the factory address. function _contractDeployer() internal view returns (address) { - return deployer; + if (address(this).code.length == 0) { + try IContractDeployer(msg.sender).getContractDeployer(address(this)) returns (address deployer) { + return deployer; + } catch { + return address(0); + } + } + return address(0); } } diff --git a/src/test/ThirdwebContract.t.sol b/src/test/ThirdwebContract.t.sol new file mode 100644 index 000000000..f61a5b144 --- /dev/null +++ b/src/test/ThirdwebContract.t.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.11; + +// Test imports +import "./utils/BaseTest.sol"; +import "contracts/TWFactory.sol"; +import "contracts/TWRegistry.sol"; + +// Helpers +import "@openzeppelin/contracts/utils/Create2.sol"; +import "@openzeppelin/contracts/proxy/Clones.sol"; +import "contracts/TWProxy.sol"; +import "contracts/ThirdwebContract.sol"; + +contract MyThirdwebContract is ThirdwebContract { + address public contractDeployerFromConstructor; + + constructor() { + contractDeployerFromConstructor = _contractDeployer(); + } + + function getContractDeployerOutsideFromConstructor() public view returns (address) { + return _contractDeployer(); + } +} + +contract ThirdwebContractTest is BaseTest { + function setUp() public override { + super.setUp(); + } + + function getContractDeployer(address) public pure returns (address) { + return address(42); + } + + function deployContract() public returns (address) { + return Create2.deploy(0, keccak256(abi.encode(0)), type(MyThirdwebContract).creationCode); + } + + function test_ThirdwebContract_ContractDeployerConstructor() external { + address addy = deployContract(); + address contractDeployer = MyThirdwebContract(addy).contractDeployerFromConstructor(); + address contractDeployerNotConstructor = MyThirdwebContract(addy).getContractDeployerOutsideFromConstructor(); + + assertEq(contractDeployer, getContractDeployer(addy)); + assertEq(contractDeployerNotConstructor, address(0)); + } +} From bf7b8d7c59a6fa6153b9523795b21b9021e1c25b Mon Sep 17 00:00:00 2001 From: Krishang Nadgauda Date: Fri, 13 May 2022 17:16:23 -0400 Subject: [PATCH 07/16] use caller, not publisher, for registry.add --- contracts/ByocFactory.sol | 13 ++++++++----- docs/ByocFactory.md | 33 ++++++++++++++++++++++++++++++--- docs/IContractDeployer.md | 37 +++++++++++++++++++++++++++++++++++++ docs/ThirdwebContract.md | 14 ++++++++++++++ 4 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 docs/IContractDeployer.md diff --git a/contracts/ByocFactory.sol b/contracts/ByocFactory.sol index e46646f0f..c2e6c087c 100644 --- a/contracts/ByocFactory.sol +++ b/contracts/ByocFactory.sol @@ -90,12 +90,15 @@ contract ByocFactory is IByocFactory, ERC2771Context, Multicall, AccessControlEn uint256 _value, string memory publishMetadataUri ) external onlyUnpausedOrAdmin returns (address deployedAddress) { + + address caller = _msgSender(); + bytes32 salt = _salt == "" - ? keccak256(abi.encodePacked(_msgSender(), block.number, _implementation, _initializeData)) - : keccak256(abi.encodePacked(_msgSender(), _salt)); + ? keccak256(abi.encodePacked(caller, block.number, _implementation, _initializeData)) + : keccak256(abi.encodePacked(caller, _salt)); address computedContractAddress = Clones.predictDeterministicAddress(_implementation, salt, address(this)); - getContractDeployer[computedContractAddress] = _msgSender(); + getContractDeployer[computedContractAddress] = caller; deployedAddress = Clones.cloneDeterministic(_implementation, salt); @@ -106,14 +109,14 @@ contract ByocFactory is IByocFactory, ERC2771Context, Multicall, AccessControlEn "Not a thirdweb contract" ); - registry.add(_publisher, deployedAddress); + registry.add(caller, deployedAddress); if (_initializeData.length > 0) { // slither-disable-next-line unused-return Address.functionCallWithValue(deployedAddress, _initializeData, _value); } - emit ContractDeployed(_msgSender(), _publisher, deployedAddress); + emit ContractDeployed(caller, _publisher, deployedAddress); } /*/////////////////////////////////////////////////////////////// diff --git a/docs/ByocFactory.md b/docs/ByocFactory.md index 226f8ad3a..94593efa8 100644 --- a/docs/ByocFactory.md +++ b/docs/ByocFactory.md @@ -81,16 +81,21 @@ Deploys a clone pointing to an implementation of a published contract. |---|---|---| | deployedAddress | address | undefined -### deployer +### getContractDeployer ```solidity -function deployer() external view returns (address) +function getContractDeployer(address) external view returns (address) ``` -*Empty var used in deployment.* +*contract address deployed through the factory => deployer* +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _0 | address | undefined #### Returns @@ -244,6 +249,28 @@ function isTrustedForwarder(address forwarder) external view returns (bool) |---|---|---| | _0 | bool | undefined +### multicall + +```solidity +function multicall(bytes[] data) external nonpayable returns (bytes[] results) +``` + + + +*Receives and executes a batch of function calls on this contract.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| data | bytes[] | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| results | bytes[] | undefined + ### renounceRole ```solidity diff --git a/docs/IContractDeployer.md b/docs/IContractDeployer.md new file mode 100644 index 000000000..a9429338b --- /dev/null +++ b/docs/IContractDeployer.md @@ -0,0 +1,37 @@ +# IContractDeployer + + + + + + + + + +## Methods + +### getContractDeployer + +```solidity +function getContractDeployer(address _contract) external view returns (address) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _contract | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | address | undefined + + + + diff --git a/docs/ThirdwebContract.md b/docs/ThirdwebContract.md index aefa9465b..1d22372d5 100644 --- a/docs/ThirdwebContract.md +++ b/docs/ThirdwebContract.md @@ -46,3 +46,17 @@ function setPublishMetadataUri(string uri) external nonpayable +## Errors + +### ThirdwebContract_MetadataAlreadyInitialized + +```solidity +error ThirdwebContract_MetadataAlreadyInitialized() +``` + + + + + + + From c84e1bcd14f6931b197f0212779e6801f57f68a8 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Fri, 13 May 2022 15:06:36 -0700 Subject: [PATCH 08/16] switch to msgSender in deployInstance as well --- contracts/ByocFactory.sol | 13 +++++++------ contracts/ThirdwebContract.sol | 1 - 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/contracts/ByocFactory.sol b/contracts/ByocFactory.sol index c2e6c087c..595fd429b 100644 --- a/contracts/ByocFactory.sol +++ b/contracts/ByocFactory.sol @@ -59,13 +59,15 @@ contract ByocFactory is IByocFactory, ERC2771Context, Multicall, AccessControlEn ) external onlyUnpausedOrAdmin returns (address deployedAddress) { require(bytes(publishMetadataUri).length > 0, "No publish metadata"); + address caller = _msgSender(); + bytes memory contractBytecode = abi.encodePacked(_contractBytecode, _constructorArgs); bytes32 salt = _salt == "" - ? keccak256(abi.encodePacked(_msgSender(), block.number, keccak256(contractBytecode))) - : keccak256(abi.encodePacked(_msgSender(), _salt)); + ? keccak256(abi.encodePacked(caller, block.number, keccak256(contractBytecode))) + : keccak256(abi.encodePacked(caller, _salt)); address computedContractAddress = Create2.computeAddress(salt, keccak256(contractBytecode), address(this)); - getContractDeployer[computedContractAddress] = _msgSender(); + getContractDeployer[computedContractAddress] = caller; deployedAddress = Create2.deploy(_value, salt, contractBytecode); @@ -76,9 +78,9 @@ contract ByocFactory is IByocFactory, ERC2771Context, Multicall, AccessControlEn "Not a thirdweb contract" ); - registry.add(_publisher, deployedAddress); + registry.add(caller, deployedAddress); - emit ContractDeployed(_msgSender(), _publisher, deployedAddress); + emit ContractDeployed(caller, _publisher, deployedAddress); } /// @notice Deploys a clone pointing to an implementation of a published contract. @@ -90,7 +92,6 @@ contract ByocFactory is IByocFactory, ERC2771Context, Multicall, AccessControlEn uint256 _value, string memory publishMetadataUri ) external onlyUnpausedOrAdmin returns (address deployedAddress) { - address caller = _msgSender(); bytes32 salt = _salt == "" diff --git a/contracts/ThirdwebContract.sol b/contracts/ThirdwebContract.sol index e93d9c51b..eb86ae462 100644 --- a/contracts/ThirdwebContract.sol +++ b/contracts/ThirdwebContract.sol @@ -25,7 +25,6 @@ contract ThirdwebContract { } /// @dev Enable access to the original contract deployer in the constructor. If this function is called outside of a constructor, it will return address(0) instead. - /// Save 1 storage slot from not storing the factory address and not having to hardcode the factory address. function _contractDeployer() internal view returns (address) { if (address(this).code.length == 0) { try IContractDeployer(msg.sender).getContractDeployer(address(this)) returns (address deployer) { From 04a4f9b68f66a235b68a941ec8ee2dd4b4848d2e Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Fri, 13 May 2022 22:43:20 -0700 Subject: [PATCH 09/16] dev build --- contracts/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/package.json b/contracts/package.json index 0816a677e..0dccc8624 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -1,7 +1,7 @@ { "name": "@thirdweb-dev/contracts", "description": "Collection of smart contracts deployable via the thirdweb SDK, dashboard and CLI", - "version": "2.3.6", + "version": "2.3.7-0", "license": "Apache-2.0", "repository": { "type": "git", From 36818f7cbc9ac5b91712d343c8d946c37e97e324 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Thu, 19 May 2022 15:58:48 -0700 Subject: [PATCH 10/16] Introduce ContractMetadataRegistry and refactor thirdweb deploy infrastructure --- .../{ByocFactory.sol => ContractDeployer.sol} | 51 +- contracts/ContractMetadataRegistry.sol | 60 ++ ...ByocRegistry.sol => ContractPublisher.sol} | 4 +- contracts/ThirdwebContract.sol | 29 +- ...IByocFactory.sol => IContractDeployer.sol} | 6 +- .../interfaces/IContractMetadataRegistry.sol | 9 + ...yocRegistry.sol => IContractPublisher.sol} | 2 +- docs/ContractDeployer.md | 439 ++++++++++++ docs/ContractMetadataRegistry.md | 369 ++++++++++ docs/ContractPublisher.md | 669 ++++++++++++++++++ docs/IContractDeployer.md | 91 +++ docs/IContractMetadataRegistry.md | 52 ++ docs/IContractPublisher.md | 341 +++++++++ docs/IContractRegistry.md | 37 + docs/ThirdwebContract.md | 44 +- scripts/deploy/byocSetup.ts | 56 +- 16 files changed, 2187 insertions(+), 72 deletions(-) rename contracts/{ByocFactory.sol => ContractDeployer.sol} (77%) create mode 100644 contracts/ContractMetadataRegistry.sol rename contracts/{ByocRegistry.sol => ContractPublisher.sol} (98%) rename contracts/interfaces/{IByocFactory.sol => IContractDeployer.sol} (95%) create mode 100644 contracts/interfaces/IContractMetadataRegistry.sol rename contracts/interfaces/{IByocRegistry.sol => IContractPublisher.sol} (99%) create mode 100644 docs/ContractDeployer.md create mode 100644 docs/ContractMetadataRegistry.md create mode 100644 docs/ContractPublisher.md create mode 100644 docs/IContractMetadataRegistry.md create mode 100644 docs/IContractPublisher.md create mode 100644 docs/IContractRegistry.md diff --git a/contracts/ByocFactory.sol b/contracts/ContractDeployer.sol similarity index 77% rename from contracts/ByocFactory.sol rename to contracts/ContractDeployer.sol index 595fd429b..961a8d9e0 100644 --- a/contracts/ByocFactory.sol +++ b/contracts/ContractDeployer.sol @@ -10,24 +10,26 @@ import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; import "@openzeppelin/contracts/metatx/ERC2771Context.sol"; // ========== Internal imports ========== -import { IByocFactory } from "./interfaces/IByocFactory.sol"; +import { IContractDeployer } from "./interfaces/IContractDeployer.sol"; import { TWRegistry } from "./TWRegistry.sol"; -import "./ThirdwebContract.sol"; +import { IContractMetadataRegistry } from "./interfaces/IContractMetadataRegistry.sol"; +import { ThirdwebContract } from "./ThirdwebContract.sol"; -contract ByocFactory is IByocFactory, ERC2771Context, Multicall, AccessControlEnumerable { +contract ContractDeployer is IContractDeployer, ERC2771Context, Multicall, AccessControlEnumerable { /*/////////////////////////////////////////////////////////////// State variables //////////////////////////////////////////////////////////////*/ /// @dev The main thirdweb registry. TWRegistry private immutable registry; + /// @dev The contract metadta registry. + IContractMetadataRegistry private immutable metadataRegistry; + /// @dev contract address deployed through the factory => deployer + mapping(address => address) public getContractDeployer; /// @dev Whether the registry is paused. bool public isPaused; - /// @dev contract address deployed through the factory => deployer - mapping(address => address) public getContractDeployer; - /*/////////////////////////////////////////////////////////////// Constructor + modifiers //////////////////////////////////////////////////////////////*/ @@ -39,8 +41,13 @@ contract ByocFactory is IByocFactory, ERC2771Context, Multicall, AccessControlEn _; } - constructor(address _twRegistry, address _trustedForwarder) ERC2771Context(_trustedForwarder) { + constructor( + address _twRegistry, + address _metadataRegistry, + address _trustedForwarder + ) ERC2771Context(_trustedForwarder) { registry = TWRegistry(_twRegistry); + metadataRegistry = IContractMetadataRegistry(_metadataRegistry); _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); } @@ -66,18 +73,20 @@ contract ByocFactory is IByocFactory, ERC2771Context, Multicall, AccessControlEn ? keccak256(abi.encodePacked(caller, block.number, keccak256(contractBytecode))) : keccak256(abi.encodePacked(caller, _salt)); + // compute the address of the clone and save it address computedContractAddress = Create2.computeAddress(salt, keccak256(contractBytecode), address(this)); getContractDeployer[computedContractAddress] = caller; + // deploy the contract deployedAddress = Create2.deploy(_value, salt, contractBytecode); - ThirdwebContract(deployedAddress).setPublishMetadataUri(publishMetadataUri); - require( - keccak256(bytes(ThirdwebContract(deployedAddress).getPublishMetadataUri())) == - keccak256(bytes(publishMetadataUri)), - "Not a thirdweb contract" - ); + // set the owner + ThirdwebContract(deployedAddress).tw_initializeOwner(caller); + // register to metadata registry + metadataRegistry.registerMetadata(deployedAddress, publishMetadataUri); + + // register to TWRegistry registry.add(caller, deployedAddress); emit ContractDeployed(caller, _publisher, deployedAddress); @@ -92,24 +101,28 @@ contract ByocFactory is IByocFactory, ERC2771Context, Multicall, AccessControlEn uint256 _value, string memory publishMetadataUri ) external onlyUnpausedOrAdmin returns (address deployedAddress) { + require(bytes(publishMetadataUri).length > 0, "No publish metadata"); + address caller = _msgSender(); bytes32 salt = _salt == "" ? keccak256(abi.encodePacked(caller, block.number, _implementation, _initializeData)) : keccak256(abi.encodePacked(caller, _salt)); + // compute the address of the clone and save it address computedContractAddress = Clones.predictDeterministicAddress(_implementation, salt, address(this)); getContractDeployer[computedContractAddress] = caller; + // deploy the clone deployedAddress = Clones.cloneDeterministic(_implementation, salt); - ThirdwebContract(deployedAddress).setPublishMetadataUri(publishMetadataUri); - require( - keccak256(bytes(ThirdwebContract(deployedAddress).getPublishMetadataUri())) == - keccak256(bytes(publishMetadataUri)), - "Not a thirdweb contract" - ); + // set the owner + ThirdwebContract(deployedAddress).tw_initializeOwner(caller); + + // register to metadata registry + metadataRegistry.registerMetadata(deployedAddress, publishMetadataUri); + // register to TWRegistry registry.add(caller, deployedAddress); if (_initializeData.length > 0) { diff --git a/contracts/ContractMetadataRegistry.sol b/contracts/ContractMetadataRegistry.sol new file mode 100644 index 000000000..215ddeefc --- /dev/null +++ b/contracts/ContractMetadataRegistry.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.11; + +// ========== External imports ========== +import "@openzeppelin/contracts/utils/Multicall.sol"; +import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; +import "@openzeppelin/contracts/metatx/ERC2771Context.sol"; + +// ========== Internal imports ========== +import { IContractMetadataRegistry } from "./interfaces/IContractMetadataRegistry.sol"; + +contract ContractMetadataRegistry is IContractMetadataRegistry, ERC2771Context, Multicall, AccessControlEnumerable { + bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); + + /*/////////////////////////////////////////////////////////////// + State variables + //////////////////////////////////////////////////////////////*/ + + /// @dev contract address deployed => metadata uri + mapping(address => string) public getMetadataUri; + + /*/////////////////////////////////////////////////////////////// + Constructor + modifiers + //////////////////////////////////////////////////////////////*/ + + /// @dev Checks whether the caller is a contract admin. + modifier onlyAdmin() { + require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Must be admin"); + + _; + } + + constructor(address _trustedForwarder) ERC2771Context(_trustedForwarder) { + _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); + } + + /*/////////////////////////////////////////////////////////////// + External methods + //////////////////////////////////////////////////////////////*/ + + function registerMetadata(address contractAddress, string memory metadataUri) external onlyAdmin { + require(hasRole(OPERATOR_ROLE, _msgSender()), "not operator."); + require(bytes(metadataUri).length > 0, "No metadata"); + require(bytes(getMetadataUri[contractAddress]).length == 0, "Metadata already registered"); + getMetadataUri[contractAddress] = metadataUri; + emit MetadataRegistered(contractAddress, metadataUri); + } + + /*/////////////////////////////////////////////////////////////// + Miscellaneous + //////////////////////////////////////////////////////////////*/ + + function _msgSender() internal view virtual override(Context, ERC2771Context) returns (address sender) { + return ERC2771Context._msgSender(); + } + + function _msgData() internal view virtual override(Context, ERC2771Context) returns (bytes calldata) { + return ERC2771Context._msgData(); + } +} diff --git a/contracts/ByocRegistry.sol b/contracts/ContractPublisher.sol similarity index 98% rename from contracts/ByocRegistry.sol rename to contracts/ContractPublisher.sol index 4afb3b04d..8fb5878a4 100644 --- a/contracts/ByocRegistry.sol +++ b/contracts/ContractPublisher.sol @@ -8,9 +8,9 @@ import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/utils/Multicall.sol"; // ========== Internal imports ========== -import { IByocRegistry } from "./interfaces/IByocRegistry.sol"; +import { IContractPublisher } from "./interfaces/IContractPublisher.sol"; -contract ByocRegistry is IByocRegistry, ERC2771Context, AccessControlEnumerable, Multicall { +contract ContractPublisher is IContractPublisher, ERC2771Context, AccessControlEnumerable, Multicall { using EnumerableSet for EnumerableSet.Bytes32Set; /*/////////////////////////////////////////////////////////////// diff --git a/contracts/ThirdwebContract.sol b/contracts/ThirdwebContract.sol index eb86ae462..1c52b55b8 100644 --- a/contracts/ThirdwebContract.sol +++ b/contracts/ThirdwebContract.sol @@ -1,27 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; -interface IContractDeployer { - function getContractDeployer(address _contract) external view returns (address); -} - -error ThirdwebContract_MetadataAlreadyInitialized(); +import "./feature/Ownable.sol"; +import "./interfaces/IContractDeployer.sol"; -contract ThirdwebContract { - /// @dev The publish metadata of the contract of which this contract is an instance. - string private publishMetadataUri; +contract ThirdwebContract is Ownable { + uint256 private hasSetOwner; - /// @dev Returns the publish metadata for this contract. - function getPublishMetadataUri() external view returns (string memory) { - return publishMetadataUri; + /// @dev Initializes the owner of the contract. + function tw_initializeOwner(address deployer) external { + require(hasSetOwner == 0, "Owner already initialized"); + hasSetOwner = 1; + owner = deployer; } - /// @dev Initializes the publish metadata and at deploy time. - function setPublishMetadataUri(string memory uri) external { - if (bytes(publishMetadataUri).length != 0) { - revert ThirdwebContract_MetadataAlreadyInitialized(); - } - publishMetadataUri = uri; + /// @dev Returns whether owner can be set + function _canSetOwner() internal virtual override returns (bool) { + return msg.sender == owner; } /// @dev Enable access to the original contract deployer in the constructor. If this function is called outside of a constructor, it will return address(0) instead. diff --git a/contracts/interfaces/IByocFactory.sol b/contracts/interfaces/IContractDeployer.sol similarity index 95% rename from contracts/interfaces/IByocFactory.sol rename to contracts/interfaces/IContractDeployer.sol index 3027fbe37..38083b2c3 100644 --- a/contracts/interfaces/IByocFactory.sol +++ b/contracts/interfaces/IContractDeployer.sol @@ -1,9 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.11; -import "../ThirdwebContract.sol"; - -interface IByocFactory { +interface IContractDeployer { /// @dev Emitted when the registry is paused. event Paused(bool isPaused); @@ -51,4 +49,6 @@ interface IByocFactory { uint256 value, string memory publishMetadataUri ) external returns (address deployedAddress); + + function getContractDeployer(address _contract) external view returns (address); } diff --git a/contracts/interfaces/IContractMetadataRegistry.sol b/contracts/interfaces/IContractMetadataRegistry.sol new file mode 100644 index 000000000..d85a45743 --- /dev/null +++ b/contracts/interfaces/IContractMetadataRegistry.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.11; + +interface IContractMetadataRegistry { + /// @dev Emitted when a contract metadata is registered + event MetadataRegistered(address indexed contractAddress, string metadataUri); + + function registerMetadata(address contractAddress, string memory metadataUri) external; +} diff --git a/contracts/interfaces/IByocRegistry.sol b/contracts/interfaces/IContractPublisher.sol similarity index 99% rename from contracts/interfaces/IByocRegistry.sol rename to contracts/interfaces/IContractPublisher.sol index 5ecb057c5..23604cd6b 100644 --- a/contracts/interfaces/IByocRegistry.sol +++ b/contracts/interfaces/IContractPublisher.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.11; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -interface IByocRegistry { +interface IContractPublisher { struct CustomContractInstance { string contractId; uint256 publishTimestamp; diff --git a/docs/ContractDeployer.md b/docs/ContractDeployer.md new file mode 100644 index 000000000..98f91b3b1 --- /dev/null +++ b/docs/ContractDeployer.md @@ -0,0 +1,439 @@ +# ContractDeployer + + + + + + + + + +## Methods + +### DEFAULT_ADMIN_ROLE + +```solidity +function DEFAULT_ADMIN_ROLE() external view returns (bytes32) +``` + + + + + + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bytes32 | undefined + +### deployInstance + +```solidity +function deployInstance(address _publisher, bytes _contractBytecode, bytes _constructorArgs, bytes32 _salt, uint256 _value, string publishMetadataUri) external nonpayable returns (address deployedAddress) +``` + +Deploys an instance of a published contract directly. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _publisher | address | undefined +| _contractBytecode | bytes | undefined +| _constructorArgs | bytes | undefined +| _salt | bytes32 | undefined +| _value | uint256 | undefined +| publishMetadataUri | string | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| deployedAddress | address | undefined + +### deployInstanceProxy + +```solidity +function deployInstanceProxy(address _publisher, address _implementation, bytes _initializeData, bytes32 _salt, uint256 _value, string publishMetadataUri) external nonpayable returns (address deployedAddress) +``` + +Deploys a clone pointing to an implementation of a published contract. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _publisher | address | undefined +| _implementation | address | undefined +| _initializeData | bytes | undefined +| _salt | bytes32 | undefined +| _value | uint256 | undefined +| publishMetadataUri | string | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| deployedAddress | address | undefined + +### getContractDeployer + +```solidity +function getContractDeployer(address) external view returns (address) +``` + + + +*contract address deployed through the factory => deployer* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _0 | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | address | undefined + +### getRoleAdmin + +```solidity +function getRoleAdmin(bytes32 role) external view returns (bytes32) +``` + + + +*Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bytes32 | undefined + +### getRoleMember + +```solidity +function getRoleMember(bytes32 role, uint256 index) external view returns (address) +``` + + + +*Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| index | uint256 | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | address | undefined + +### getRoleMemberCount + +```solidity +function getRoleMemberCount(bytes32 role) external view returns (uint256) +``` + + + +*Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | uint256 | undefined + +### grantRole + +```solidity +function grantRole(bytes32 role, address account) external nonpayable +``` + + + +*Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +### hasRole + +```solidity +function hasRole(bytes32 role, address account) external view returns (bool) +``` + + + +*Returns `true` if `account` has been granted `role`.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + +### isPaused + +```solidity +function isPaused() external view returns (bool) +``` + + + +*Whether the registry is paused.* + + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + +### isTrustedForwarder + +```solidity +function isTrustedForwarder(address forwarder) external view returns (bool) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| forwarder | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + +### multicall + +```solidity +function multicall(bytes[] data) external nonpayable returns (bytes[] results) +``` + + + +*Receives and executes a batch of function calls on this contract.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| data | bytes[] | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| results | bytes[] | undefined + +### renounceRole + +```solidity +function renounceRole(bytes32 role, address account) external nonpayable +``` + + + +*Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +### revokeRole + +```solidity +function revokeRole(bytes32 role, address account) external nonpayable +``` + + + +*Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +### setPause + +```solidity +function setPause(bool _pause) external nonpayable +``` + + + +*Lets a contract admin pause the registry.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _pause | bool | undefined + +### supportsInterface + +```solidity +function supportsInterface(bytes4 interfaceId) external view returns (bool) +``` + + + +*See {IERC165-supportsInterface}.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| interfaceId | bytes4 | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + + + +## Events + +### ContractDeployed + +```solidity +event ContractDeployed(address indexed deployer, address indexed publisher, address deployedContract) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| deployer `indexed` | address | undefined | +| publisher `indexed` | address | undefined | +| deployedContract | address | undefined | + +### Paused + +```solidity +event Paused(bool isPaused) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| isPaused | bool | undefined | + +### RoleAdminChanged + +```solidity +event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role `indexed` | bytes32 | undefined | +| previousAdminRole `indexed` | bytes32 | undefined | +| newAdminRole `indexed` | bytes32 | undefined | + +### RoleGranted + +```solidity +event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role `indexed` | bytes32 | undefined | +| account `indexed` | address | undefined | +| sender `indexed` | address | undefined | + +### RoleRevoked + +```solidity +event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role `indexed` | bytes32 | undefined | +| account `indexed` | address | undefined | +| sender `indexed` | address | undefined | + + + diff --git a/docs/ContractMetadataRegistry.md b/docs/ContractMetadataRegistry.md new file mode 100644 index 000000000..21931edc3 --- /dev/null +++ b/docs/ContractMetadataRegistry.md @@ -0,0 +1,369 @@ +# ContractMetadataRegistry + + + + + + + + + +## Methods + +### DEFAULT_ADMIN_ROLE + +```solidity +function DEFAULT_ADMIN_ROLE() external view returns (bytes32) +``` + + + + + + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bytes32 | undefined + +### OPERATOR_ROLE + +```solidity +function OPERATOR_ROLE() external view returns (bytes32) +``` + + + + + + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bytes32 | undefined + +### getMetadataUri + +```solidity +function getMetadataUri(address) external view returns (string) +``` + + + +*contract address deployed => metadata uri* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _0 | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | string | undefined + +### getRoleAdmin + +```solidity +function getRoleAdmin(bytes32 role) external view returns (bytes32) +``` + + + +*Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bytes32 | undefined + +### getRoleMember + +```solidity +function getRoleMember(bytes32 role, uint256 index) external view returns (address) +``` + + + +*Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| index | uint256 | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | address | undefined + +### getRoleMemberCount + +```solidity +function getRoleMemberCount(bytes32 role) external view returns (uint256) +``` + + + +*Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | uint256 | undefined + +### grantRole + +```solidity +function grantRole(bytes32 role, address account) external nonpayable +``` + + + +*Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +### hasRole + +```solidity +function hasRole(bytes32 role, address account) external view returns (bool) +``` + + + +*Returns `true` if `account` has been granted `role`.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + +### isTrustedForwarder + +```solidity +function isTrustedForwarder(address forwarder) external view returns (bool) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| forwarder | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + +### multicall + +```solidity +function multicall(bytes[] data) external nonpayable returns (bytes[] results) +``` + + + +*Receives and executes a batch of function calls on this contract.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| data | bytes[] | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| results | bytes[] | undefined + +### registerMetadata + +```solidity +function registerMetadata(address contractAddress, string metadataUri) external nonpayable +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| contractAddress | address | undefined +| metadataUri | string | undefined + +### renounceRole + +```solidity +function renounceRole(bytes32 role, address account) external nonpayable +``` + + + +*Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +### revokeRole + +```solidity +function revokeRole(bytes32 role, address account) external nonpayable +``` + + + +*Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +### supportsInterface + +```solidity +function supportsInterface(bytes4 interfaceId) external view returns (bool) +``` + + + +*See {IERC165-supportsInterface}.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| interfaceId | bytes4 | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + + + +## Events + +### MetadataRegistered + +```solidity +event MetadataRegistered(address indexed contractAddress, string metadataUri) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| contractAddress `indexed` | address | undefined | +| metadataUri | string | undefined | + +### RoleAdminChanged + +```solidity +event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role `indexed` | bytes32 | undefined | +| previousAdminRole `indexed` | bytes32 | undefined | +| newAdminRole `indexed` | bytes32 | undefined | + +### RoleGranted + +```solidity +event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role `indexed` | bytes32 | undefined | +| account `indexed` | address | undefined | +| sender `indexed` | address | undefined | + +### RoleRevoked + +```solidity +event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role `indexed` | bytes32 | undefined | +| account `indexed` | address | undefined | +| sender `indexed` | address | undefined | + + + diff --git a/docs/ContractPublisher.md b/docs/ContractPublisher.md new file mode 100644 index 000000000..04405551d --- /dev/null +++ b/docs/ContractPublisher.md @@ -0,0 +1,669 @@ +# ContractPublisher + + + + + + + + + +## Methods + +### DEFAULT_ADMIN_ROLE + +```solidity +function DEFAULT_ADMIN_ROLE() external view returns (bytes32) +``` + + + + + + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bytes32 | undefined + +### addToPublicList + +```solidity +function addToPublicList(address _publisher, string _contractId) external nonpayable +``` + +Lets an account add a published contract (and all its versions). The account must be approved by the publisher, or be the publisher. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _publisher | address | undefined +| _contractId | string | undefined + +### approveOperator + +```solidity +function approveOperator(address _operator, bool _toApprove) external nonpayable +``` + +Lets a publisher (caller) approve an operator to publish / unpublish contracts on their behalf. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _operator | address | undefined +| _toApprove | bool | undefined + +### getAllPublicPublishedContracts + +```solidity +function getAllPublicPublishedContracts() external view returns (struct IContractPublisher.CustomContractInstance[] published) +``` + +Returns the latest version of all contracts published by a publisher. + + + + +#### Returns + +| Name | Type | Description | +|---|---|---| +| published | IContractPublisher.CustomContractInstance[] | undefined + +### getAllPublishedContracts + +```solidity +function getAllPublishedContracts(address _publisher) external view returns (struct IContractPublisher.CustomContractInstance[] published) +``` + +Returns the latest version of all contracts published by a publisher. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _publisher | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| published | IContractPublisher.CustomContractInstance[] | undefined + +### getPublicId + +```solidity +function getPublicId(address _publisher, string _contractId) external view returns (uint256 publicId) +``` + +Returns the public id of a published contract, if it is public. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _publisher | address | undefined +| _contractId | string | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| publicId | uint256 | undefined + +### getPublishedContract + +```solidity +function getPublishedContract(address _publisher, string _contractId) external view returns (struct IContractPublisher.CustomContractInstance published) +``` + +Returns the latest version of a contract published by a publisher. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _publisher | address | undefined +| _contractId | string | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| published | IContractPublisher.CustomContractInstance | undefined + +### getPublishedContractVersions + +```solidity +function getPublishedContractVersions(address _publisher, string _contractId) external view returns (struct IContractPublisher.CustomContractInstance[] published) +``` + +Returns all versions of a published contract. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _publisher | address | undefined +| _contractId | string | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| published | IContractPublisher.CustomContractInstance[] | undefined + +### getRoleAdmin + +```solidity +function getRoleAdmin(bytes32 role) external view returns (bytes32) +``` + + + +*Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bytes32 | undefined + +### getRoleMember + +```solidity +function getRoleMember(bytes32 role, uint256 index) external view returns (address) +``` + + + +*Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| index | uint256 | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | address | undefined + +### getRoleMemberCount + +```solidity +function getRoleMemberCount(bytes32 role) external view returns (uint256) +``` + + + +*Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | uint256 | undefined + +### grantRole + +```solidity +function grantRole(bytes32 role, address account) external nonpayable +``` + + + +*Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +### hasRole + +```solidity +function hasRole(bytes32 role, address account) external view returns (bool) +``` + + + +*Returns `true` if `account` has been granted `role`.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + +### isApprovedByPublisher + +```solidity +function isApprovedByPublisher(address, address) external view returns (bool) +``` + + + +*Mapping from publisher address => operator address => whether publisher has approved operator to publish / unpublish contracts on their behalf.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _0 | address | undefined +| _1 | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + +### isPaused + +```solidity +function isPaused() external view returns (bool) +``` + + + +*Whether the registry is paused.* + + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + +### isTrustedForwarder + +```solidity +function isTrustedForwarder(address forwarder) external view returns (bool) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| forwarder | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + +### multicall + +```solidity +function multicall(bytes[] data) external nonpayable returns (bytes[] results) +``` + + + +*Receives and executes a batch of function calls on this contract.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| data | bytes[] | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| results | bytes[] | undefined + +### nextPublicId + +```solidity +function nextPublicId() external view returns (uint256) +``` + + + +*The global Id for publicly published contracts.* + + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | uint256 | undefined + +### publishContract + +```solidity +function publishContract(address _publisher, string _publishMetadataUri, bytes32 _bytecodeHash, address _implementation, string _contractId) external nonpayable +``` + +Let's an account publish a contract. The account must be approved by the publisher, or be the publisher. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _publisher | address | undefined +| _publishMetadataUri | string | undefined +| _bytecodeHash | bytes32 | undefined +| _implementation | address | undefined +| _contractId | string | undefined + +### removeFromPublicList + +```solidity +function removeFromPublicList(address _publisher, string _contractId) external nonpayable +``` + +Lets an account remove a published contract (and all its versions). The account must be approved by the publisher, or be the publisher. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _publisher | address | undefined +| _contractId | string | undefined + +### renounceRole + +```solidity +function renounceRole(bytes32 role, address account) external nonpayable +``` + + + +*Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `account`.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +### revokeRole + +```solidity +function revokeRole(bytes32 role, address account) external nonpayable +``` + + + +*Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role | bytes32 | undefined +| account | address | undefined + +### setPause + +```solidity +function setPause(bool _pause) external nonpayable +``` + + + +*Lets a contract admin pause the registry.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _pause | bool | undefined + +### supportsInterface + +```solidity +function supportsInterface(bytes4 interfaceId) external view returns (bool) +``` + + + +*See {IERC165-supportsInterface}.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| interfaceId | bytes4 | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | bool | undefined + +### unpublishContract + +```solidity +function unpublishContract(address _publisher, string _contractId) external nonpayable +``` + +Lets an account unpublish a contract and all its versions. The account must be approved by the publisher, or be the publisher. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _publisher | address | undefined +| _contractId | string | undefined + + + +## Events + +### AddedContractToPublicList + +```solidity +event AddedContractToPublicList(address indexed publisher, string indexed contractId) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher `indexed` | address | undefined | +| contractId `indexed` | string | undefined | + +### Approved + +```solidity +event Approved(address indexed publisher, address indexed operator, bool isApproved) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher `indexed` | address | undefined | +| operator `indexed` | address | undefined | +| isApproved | bool | undefined | + +### ContractPublished + +```solidity +event ContractPublished(address indexed operator, address indexed publisher, IContractPublisher.CustomContractInstance publishedContract) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| operator `indexed` | address | undefined | +| publisher `indexed` | address | undefined | +| publishedContract | IContractPublisher.CustomContractInstance | undefined | + +### ContractUnpublished + +```solidity +event ContractUnpublished(address indexed operator, address indexed publisher, string indexed contractId) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| operator `indexed` | address | undefined | +| publisher `indexed` | address | undefined | +| contractId `indexed` | string | undefined | + +### Paused + +```solidity +event Paused(bool isPaused) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| isPaused | bool | undefined | + +### RemovedContractToPublicList + +```solidity +event RemovedContractToPublicList(address indexed publisher, string indexed contractId) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher `indexed` | address | undefined | +| contractId `indexed` | string | undefined | + +### RoleAdminChanged + +```solidity +event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role `indexed` | bytes32 | undefined | +| previousAdminRole `indexed` | bytes32 | undefined | +| newAdminRole `indexed` | bytes32 | undefined | + +### RoleGranted + +```solidity +event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role `indexed` | bytes32 | undefined | +| account `indexed` | address | undefined | +| sender `indexed` | address | undefined | + +### RoleRevoked + +```solidity +event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| role `indexed` | bytes32 | undefined | +| account `indexed` | address | undefined | +| sender `indexed` | address | undefined | + + + diff --git a/docs/IContractDeployer.md b/docs/IContractDeployer.md index a9429338b..35ac7ff53 100644 --- a/docs/IContractDeployer.md +++ b/docs/IContractDeployer.md @@ -10,6 +10,60 @@ ## Methods +### deployInstance + +```solidity +function deployInstance(address publisher, bytes contractBytecode, bytes constructorArgs, bytes32 salt, uint256 value, string publishMetadataUri) external nonpayable returns (address deployedAddress) +``` + +Deploys an instance of a published contract directly. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher | address | The address of the publisher. +| contractBytecode | bytes | The bytecode of the contract to deploy. +| constructorArgs | bytes | The encoded constructor args to deploy the contract with. +| salt | bytes32 | The salt to use in the CREATE2 contract deployment. +| value | uint256 | The native token value to pass to the contract on deployment. +| publishMetadataUri | string | The publish metadata URI for the contract to deploy. + +#### Returns + +| Name | Type | Description | +|---|---|---| +| deployedAddress | address | The address of the contract deployed. + +### deployInstanceProxy + +```solidity +function deployInstanceProxy(address publisher, address implementation, bytes initializeData, bytes32 salt, uint256 value, string publishMetadataUri) external nonpayable returns (address deployedAddress) +``` + +Deploys a clone pointing to an implementation of a published contract. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher | address | The address of the publisher. +| implementation | address | The contract implementation for the clone to point to. +| initializeData | bytes | The encoded function call to initialize the contract with. +| salt | bytes32 | The salt to use in the CREATE2 contract deployment. +| value | uint256 | The native token value to pass to the contract on deployment. +| publishMetadataUri | string | The publish metadata URI and for the contract to deploy. + +#### Returns + +| Name | Type | Description | +|---|---|---| +| deployedAddress | address | The address of the contract deployed. + ### getContractDeployer ```solidity @@ -34,4 +88,41 @@ function getContractDeployer(address _contract) external view returns (address) +## Events + +### ContractDeployed + +```solidity +event ContractDeployed(address indexed deployer, address indexed publisher, address deployedContract) +``` + + + +*Emitted when a contract is deployed.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| deployer `indexed` | address | undefined | +| publisher `indexed` | address | undefined | +| deployedContract | address | undefined | + +### Paused + +```solidity +event Paused(bool isPaused) +``` + + + +*Emitted when the registry is paused.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| isPaused | bool | undefined | + + diff --git a/docs/IContractMetadataRegistry.md b/docs/IContractMetadataRegistry.md new file mode 100644 index 000000000..d4d609657 --- /dev/null +++ b/docs/IContractMetadataRegistry.md @@ -0,0 +1,52 @@ +# IContractMetadataRegistry + + + + + + + + + +## Methods + +### registerMetadata + +```solidity +function registerMetadata(address contractAddress, string metadataUri) external nonpayable +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| contractAddress | address | undefined +| metadataUri | string | undefined + + + +## Events + +### MetadataRegistered + +```solidity +event MetadataRegistered(address indexed contractAddress, string metadataUri) +``` + + + +*Emitted when a contract metadata is registered* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| contractAddress `indexed` | address | undefined | +| metadataUri | string | undefined | + + + diff --git a/docs/IContractPublisher.md b/docs/IContractPublisher.md new file mode 100644 index 000000000..99a734aed --- /dev/null +++ b/docs/IContractPublisher.md @@ -0,0 +1,341 @@ +# IContractPublisher + + + + + + + + + +## Methods + +### addToPublicList + +```solidity +function addToPublicList(address publisher, string contractId) external nonpayable +``` + +Lets an account add a published contract (and all its versions). The account must be approved by the publisher, or be the publisher. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher | address | The address of the publisher. +| contractId | string | The identifier for a published contract (that can have multiple verisons). + +### approveOperator + +```solidity +function approveOperator(address operator, bool toApprove) external nonpayable +``` + +Lets a publisher (caller) approve an operator to publish / unpublish contracts on their behalf. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| operator | address | The address of the operator who publishes/unpublishes on behalf of the publisher. +| toApprove | bool | whether to an operator to publish / unpublish contracts on the publisher's behalf. + +### getAllPublicPublishedContracts + +```solidity +function getAllPublicPublishedContracts() external view returns (struct IContractPublisher.CustomContractInstance[] published) +``` + +Returns the latest version of all contracts published by a publisher. + + + + +#### Returns + +| Name | Type | Description | +|---|---|---| +| published | IContractPublisher.CustomContractInstance[] | An array of all contracts published by the publisher. + +### getAllPublishedContracts + +```solidity +function getAllPublishedContracts(address publisher) external view returns (struct IContractPublisher.CustomContractInstance[] published) +``` + +Returns the latest version of all contracts published by a publisher. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher | address | The address of the publisher. + +#### Returns + +| Name | Type | Description | +|---|---|---| +| published | IContractPublisher.CustomContractInstance[] | An array of all contracts published by the publisher. + +### getPublicId + +```solidity +function getPublicId(address publisher, string contractId) external nonpayable returns (uint256 publicId) +``` + +Returns the public id of a published contract, if it is public. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher | address | The address of the publisher. +| contractId | string | The identifier for a published contract (that can have multiple verisons). + +#### Returns + +| Name | Type | Description | +|---|---|---| +| publicId | uint256 | the public id of a published contract. + +### getPublishedContract + +```solidity +function getPublishedContract(address publisher, string contractId) external view returns (struct IContractPublisher.CustomContractInstance published) +``` + +Returns the latest version of a contract published by a publisher. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher | address | The address of the publisher. +| contractId | string | The identifier for a published contract (that can have multiple verisons). + +#### Returns + +| Name | Type | Description | +|---|---|---| +| published | IContractPublisher.CustomContractInstance | The desired contract published by the publisher. + +### getPublishedContractVersions + +```solidity +function getPublishedContractVersions(address publisher, string contractId) external view returns (struct IContractPublisher.CustomContractInstance[] published) +``` + +Returns all versions of a published contract. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher | address | The address of the publisher. +| contractId | string | The identifier for a published contract (that can have multiple verisons). + +#### Returns + +| Name | Type | Description | +|---|---|---| +| published | IContractPublisher.CustomContractInstance[] | The desired contracts published by the publisher. + +### isApprovedByPublisher + +```solidity +function isApprovedByPublisher(address publisher, address operator) external view returns (bool isApproved) +``` + +Returns whether a publisher has approved an operator to publish / unpublish contracts on their behalf. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher | address | The address of the publisher. +| operator | address | The address of the operator who publishes/unpublishes on behalf of the publisher. + +#### Returns + +| Name | Type | Description | +|---|---|---| +| isApproved | bool | Whether the publisher has approved the operator to publish / unpublish contracts on their behalf. + +### publishContract + +```solidity +function publishContract(address publisher, string publishMetadataUri, bytes32 bytecodeHash, address implementation, string contractId) external nonpayable +``` + +Let's an account publish a contract. The account must be approved by the publisher, or be the publisher. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher | address | The address of the publisher. +| publishMetadataUri | string | The IPFS URI of the publish metadata. +| bytecodeHash | bytes32 | The keccak256 hash of the contract bytecode. +| implementation | address | (Optional) An implementation address that proxy contracts / clones can point to. Default value if such an implementation does not exist - address(0); +| contractId | string | The identifier for a published contract (that can have multiple verisons). + +### removeFromPublicList + +```solidity +function removeFromPublicList(address publisher, string contractId) external nonpayable +``` + +Lets an account remove a published contract (and all its versions). The account must be approved by the publisher, or be the publisher. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher | address | The address of the publisher. +| contractId | string | The identifier for a published contract (that can have multiple verisons). + +### unpublishContract + +```solidity +function unpublishContract(address publisher, string contractId) external nonpayable +``` + +Lets an account unpublish a contract and all its versions. The account must be approved by the publisher, or be the publisher. + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher | address | The address of the publisher. +| contractId | string | The identifier for a published contract (that can have multiple verisons). + + + +## Events + +### AddedContractToPublicList + +```solidity +event AddedContractToPublicList(address indexed publisher, string indexed contractId) +``` + + + +*Emitted when a published contract is added to the public list.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher `indexed` | address | undefined | +| contractId `indexed` | string | undefined | + +### Approved + +```solidity +event Approved(address indexed publisher, address indexed operator, bool isApproved) +``` + + + +*Emitted when a publisher's approval of an operator is updated.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher `indexed` | address | undefined | +| operator `indexed` | address | undefined | +| isApproved | bool | undefined | + +### ContractPublished + +```solidity +event ContractPublished(address indexed operator, address indexed publisher, IContractPublisher.CustomContractInstance publishedContract) +``` + + + +*Emitted when a contract is published.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| operator `indexed` | address | undefined | +| publisher `indexed` | address | undefined | +| publishedContract | IContractPublisher.CustomContractInstance | undefined | + +### ContractUnpublished + +```solidity +event ContractUnpublished(address indexed operator, address indexed publisher, string indexed contractId) +``` + + + +*Emitted when a contract is unpublished.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| operator `indexed` | address | undefined | +| publisher `indexed` | address | undefined | +| contractId `indexed` | string | undefined | + +### Paused + +```solidity +event Paused(bool isPaused) +``` + + + +*Emitted when the registry is paused.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| isPaused | bool | undefined | + +### RemovedContractToPublicList + +```solidity +event RemovedContractToPublicList(address indexed publisher, string indexed contractId) +``` + + + +*Emitted when a published contract is removed from the public list.* + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| publisher `indexed` | address | undefined | +| contractId `indexed` | string | undefined | + + + diff --git a/docs/IContractRegistry.md b/docs/IContractRegistry.md new file mode 100644 index 000000000..3e708b095 --- /dev/null +++ b/docs/IContractRegistry.md @@ -0,0 +1,37 @@ +# IContractRegistry + + + + + + + + + +## Methods + +### getPublishMetadataUri + +```solidity +function getPublishMetadataUri(address _contract) external view returns (string) +``` + + + + + +#### Parameters + +| Name | Type | Description | +|---|---|---| +| _contract | address | undefined + +#### Returns + +| Name | Type | Description | +|---|---|---| +| _0 | string | undefined + + + + diff --git a/docs/ThirdwebContract.md b/docs/ThirdwebContract.md index 1d22372d5..b67d6792b 100644 --- a/docs/ThirdwebContract.md +++ b/docs/ThirdwebContract.md @@ -10,53 +10,75 @@ ## Methods -### getPublishMetadataUri +### owner ```solidity -function getPublishMetadataUri() external view returns (string) +function owner() external view returns (address) ``` -*Returns the publish metadata for this contract.* + #### Returns | Name | Type | Description | |---|---|---| -| _0 | string | undefined +| _0 | address | undefined -### setPublishMetadataUri +### setOwner ```solidity -function setPublishMetadataUri(string uri) external nonpayable +function setOwner(address _newOwner) external nonpayable ``` -*Initializes the publish metadata and at deploy time.* +*Lets a contract admin set a new owner for the contract. The new owner must be a contract admin.* #### Parameters | Name | Type | Description | |---|---|---| -| uri | string | undefined +| _newOwner | address | undefined + +### tw_initializeOwner + +```solidity +function tw_initializeOwner(address deployer) external nonpayable +``` +*Initializes the owner of the contract.* -## Errors +#### Parameters + +| Name | Type | Description | +|---|---|---| +| deployer | address | undefined -### ThirdwebContract_MetadataAlreadyInitialized + + +## Events + +### OwnerUpdated ```solidity -error ThirdwebContract_MetadataAlreadyInitialized() +event OwnerUpdated(address prevOwner, address newOwner) ``` +#### Parameters + +| Name | Type | Description | +|---|---|---| +| prevOwner | address | undefined | +| newOwner | address | undefined | + diff --git a/scripts/deploy/byocSetup.ts b/scripts/deploy/byocSetup.ts index efd9f927d..f899f3100 100644 --- a/scripts/deploy/byocSetup.ts +++ b/scripts/deploy/byocSetup.ts @@ -2,7 +2,7 @@ import hre, { ethers } from "hardhat"; import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; -import { TWRegistry, ByocRegistry, ByocFactory } from "typechain"; +import { TWRegistry, ContractMetadataRegistry, ContractDeployer, ContractPublisher } from "typechain"; /** * NOTE: This deploy script is written for Polygon-Mumbai. @@ -27,7 +27,6 @@ async function verify(address: string, args: any[]) { } async function main() { - const [deployer]: SignerWithAddress[] = await ethers.getSigners(); console.log("Deployer address:", deployer.address); @@ -37,36 +36,55 @@ async function main() { // const registry: TWRegistry = await ethers.getContractAt("TWRegistry", registryAddress); const registry: TWRegistry = await ethers.getContractFactory("TWRegistry").then(f => f.deploy(trustedForwarder)); console.log("\nDeploying new TWRegistry \ntx: ", registry.deployTransaction.hash, "\naddress: ", registry.address); - await registry.deployTransaction.wait(); - const byocRegsitry: ByocRegistry = await ethers - .getContractFactory("ByocRegistry") + const contractMetadataRegistry: ContractMetadataRegistry = await ethers + .getContractFactory("ContractMetadataRegistry") .then(f => f.deploy(trustedForwarder)); console.log( - "Deploying ByocRegistry at tx: ", - byocRegsitry.deployTransaction.hash, + "Deploying ContractMetadataRegistry at tx: ", + contractMetadataRegistry.deployTransaction.hash, " address: ", - byocRegsitry.address, + contractMetadataRegistry.address, ); - await byocRegsitry.deployTransaction.wait(); - console.log("Deployed ByocRegistry"); + await contractMetadataRegistry.deployTransaction.wait(); + console.log("Deployed ContractMetadataRegistry"); - const byocFactory: ByocFactory = await ethers - .getContractFactory("ByocFactory") - .then(f => f.deploy(registry.address, trustedForwarder)); - console.log("\nDeploying ByocFactory \ntx: ", byocFactory.deployTransaction.hash, "\naddress: ", byocFactory.address); - await byocFactory.deployTransaction.wait(); + const contractPublisher: ContractPublisher = await ethers + .getContractFactory("ContractPublisher") + .then(f => f.deploy(trustedForwarder)); + console.log( + "Deploying ContractPublisher at tx: ", + contractPublisher.deployTransaction.hash, + " address: ", + contractPublisher.address, + ); + await contractPublisher.deployTransaction.wait(); + console.log("Deployed ContractPublisher"); - const tx = await registry.grantRole(await registry.OPERATOR_ROLE(), byocFactory.address); - console.log("\nGranting operator role to ByocFactory: ", tx.hash); + const contractDeployer: ContractDeployer = await ethers + .getContractFactory("ContractDeployer") + .then(f => f.deploy(registry.address, contractMetadataRegistry.address, trustedForwarder)); + console.log( + "\nDeploying ContractDeployer \ntx: ", + contractDeployer.deployTransaction.hash, + "\naddress: ", + contractDeployer.address, + ); + await contractDeployer.deployTransaction.wait(); + const tx = await registry.grantRole(await registry.OPERATOR_ROLE(), contractDeployer.address); + console.log("\nGranting operator role to ContractDeployer for TWRegistry: ", tx.hash); await tx.wait(); + const tx2 = await contractMetadataRegistry.grantRole(await registry.OPERATOR_ROLE(), contractDeployer.address); + console.log("\nGranting operator role to ContractDeployer for ContractMetadataRegistry: ", tx.hash); + await tx2.wait(); console.log("\nDone. Now verifying contracts:"); - // await verify(byocRegsitry.address, [trustedForwarders]); - await verify(byocFactory.address, [registry.address, trustedForwarder]); + await verify(contractPublisher.address, [trustedForwarder]); + await verify(contractMetadataRegistry.address, [trustedForwarder]); + await verify(contractDeployer.address, [registry.address, contractMetadataRegistry.address, trustedForwarder]); } main() From 038ee1aa7eb0b931e2d4ed659bad82945590d706 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Thu, 19 May 2022 16:02:44 -0700 Subject: [PATCH 11/16] change solidity versions to 0.8.0 --- contracts/ContractDeployer.sol | 2 +- contracts/ContractMetadataRegistry.sol | 2 +- contracts/ContractPublisher.sol | 2 +- contracts/interfaces/IContractDeployer.sol | 2 +- contracts/interfaces/IContractMetadataRegistry.sol | 2 +- contracts/interfaces/IContractPublisher.sol | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/ContractDeployer.sol b/contracts/ContractDeployer.sol index 961a8d9e0..a784fede9 100644 --- a/contracts/ContractDeployer.sol +++ b/contracts/ContractDeployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.11; +pragma solidity ^0.8.0; // ========== External imports ========== import "@openzeppelin/contracts/utils/Create2.sol"; diff --git a/contracts/ContractMetadataRegistry.sol b/contracts/ContractMetadataRegistry.sol index 215ddeefc..512385c50 100644 --- a/contracts/ContractMetadataRegistry.sol +++ b/contracts/ContractMetadataRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.11; +pragma solidity ^0.8.0; // ========== External imports ========== import "@openzeppelin/contracts/utils/Multicall.sol"; diff --git a/contracts/ContractPublisher.sol b/contracts/ContractPublisher.sol index 8fb5878a4..317361d97 100644 --- a/contracts/ContractPublisher.sol +++ b/contracts/ContractPublisher.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.11; +pragma solidity ^0.8.0; // ========== External imports ========== import "@openzeppelin/contracts/metatx/ERC2771Context.sol"; diff --git a/contracts/interfaces/IContractDeployer.sol b/contracts/interfaces/IContractDeployer.sol index 38083b2c3..b767cc893 100644 --- a/contracts/interfaces/IContractDeployer.sol +++ b/contracts/interfaces/IContractDeployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.11; +pragma solidity ^0.8.0; interface IContractDeployer { /// @dev Emitted when the registry is paused. diff --git a/contracts/interfaces/IContractMetadataRegistry.sol b/contracts/interfaces/IContractMetadataRegistry.sol index d85a45743..0e94cf74b 100644 --- a/contracts/interfaces/IContractMetadataRegistry.sol +++ b/contracts/interfaces/IContractMetadataRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.11; +pragma solidity ^0.8.0; interface IContractMetadataRegistry { /// @dev Emitted when a contract metadata is registered diff --git a/contracts/interfaces/IContractPublisher.sol b/contracts/interfaces/IContractPublisher.sol index 23604cd6b..c81a2f275 100644 --- a/contracts/interfaces/IContractPublisher.sol +++ b/contracts/interfaces/IContractPublisher.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.11; +pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; From b834ef99ff262310d32c7df3f6f112843baa37a3 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Thu, 19 May 2022 16:41:26 -0700 Subject: [PATCH 12/16] remove onlyAdmin requirement --- contracts/ContractMetadataRegistry.sol | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/contracts/ContractMetadataRegistry.sol b/contracts/ContractMetadataRegistry.sol index 512385c50..784e99487 100644 --- a/contracts/ContractMetadataRegistry.sol +++ b/contracts/ContractMetadataRegistry.sol @@ -23,13 +23,6 @@ contract ContractMetadataRegistry is IContractMetadataRegistry, ERC2771Context, Constructor + modifiers //////////////////////////////////////////////////////////////*/ - /// @dev Checks whether the caller is a contract admin. - modifier onlyAdmin() { - require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Must be admin"); - - _; - } - constructor(address _trustedForwarder) ERC2771Context(_trustedForwarder) { _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); } @@ -38,7 +31,7 @@ contract ContractMetadataRegistry is IContractMetadataRegistry, ERC2771Context, External methods //////////////////////////////////////////////////////////////*/ - function registerMetadata(address contractAddress, string memory metadataUri) external onlyAdmin { + function registerMetadata(address contractAddress, string memory metadataUri) external { require(hasRole(OPERATOR_ROLE, _msgSender()), "not operator."); require(bytes(metadataUri).length > 0, "No metadata"); require(bytes(getMetadataUri[contractAddress]).length == 0, "Metadata already registered"); From dfd9dbae86655143bb803f8015d6d4a17bf7ce83 Mon Sep 17 00:00:00 2001 From: Krishang Nadgauda Date: Thu, 19 May 2022 23:32:46 -0400 Subject: [PATCH 13/16] comments cleanup on ContractMetadataregistry --- contracts/ContractMetadataRegistry.sol | 13 +++++++++---- contracts/interfaces/IContractMetadataRegistry.sol | 1 + docs/ContractMetadataRegistry.md | 4 ++-- docs/IContractMetadataRegistry.md | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/contracts/ContractMetadataRegistry.sol b/contracts/ContractMetadataRegistry.sol index 784e99487..caba81eda 100644 --- a/contracts/ContractMetadataRegistry.sol +++ b/contracts/ContractMetadataRegistry.sol @@ -10,17 +10,19 @@ import "@openzeppelin/contracts/metatx/ERC2771Context.sol"; import { IContractMetadataRegistry } from "./interfaces/IContractMetadataRegistry.sol"; contract ContractMetadataRegistry is IContractMetadataRegistry, ERC2771Context, Multicall, AccessControlEnumerable { + + /// @dev Only accounts with OPERATOR_ROLE can register metadata for contracts. bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); /*/////////////////////////////////////////////////////////////// - State variables + Mappings //////////////////////////////////////////////////////////////*/ /// @dev contract address deployed => metadata uri mapping(address => string) public getMetadataUri; /*/////////////////////////////////////////////////////////////// - Constructor + modifiers + Constructor //////////////////////////////////////////////////////////////*/ constructor(address _trustedForwarder) ERC2771Context(_trustedForwarder) { @@ -28,14 +30,17 @@ contract ContractMetadataRegistry is IContractMetadataRegistry, ERC2771Context, } /*/////////////////////////////////////////////////////////////// - External methods + External functions //////////////////////////////////////////////////////////////*/ + /// @dev Records `metadataUri` as metadata for the contract at `contractAddress`. function registerMetadata(address contractAddress, string memory metadataUri) external { - require(hasRole(OPERATOR_ROLE, _msgSender()), "not operator."); + require(hasRole(OPERATOR_ROLE, _msgSender()), "Not operator."); require(bytes(metadataUri).length > 0, "No metadata"); require(bytes(getMetadataUri[contractAddress]).length == 0, "Metadata already registered"); + getMetadataUri[contractAddress] = metadataUri; + emit MetadataRegistered(contractAddress, metadataUri); } diff --git a/contracts/interfaces/IContractMetadataRegistry.sol b/contracts/interfaces/IContractMetadataRegistry.sol index 0e94cf74b..6c922c8e0 100644 --- a/contracts/interfaces/IContractMetadataRegistry.sol +++ b/contracts/interfaces/IContractMetadataRegistry.sol @@ -5,5 +5,6 @@ interface IContractMetadataRegistry { /// @dev Emitted when a contract metadata is registered event MetadataRegistered(address indexed contractAddress, string metadataUri); + /// @dev Records `metadataUri` as metadata for the contract at `contractAddress`. function registerMetadata(address contractAddress, string memory metadataUri) external; } diff --git a/docs/ContractMetadataRegistry.md b/docs/ContractMetadataRegistry.md index 21931edc3..a7af2f894 100644 --- a/docs/ContractMetadataRegistry.md +++ b/docs/ContractMetadataRegistry.md @@ -35,7 +35,7 @@ function OPERATOR_ROLE() external view returns (bytes32) - +*Only accounts with OPERATOR_ROLE can register metadata for contracts.* #### Returns @@ -225,7 +225,7 @@ function registerMetadata(address contractAddress, string metadataUri) external - +*Records `metadataUri` as metadata for the contract at `contractAddress`.* #### Parameters diff --git a/docs/IContractMetadataRegistry.md b/docs/IContractMetadataRegistry.md index d4d609657..524c0cf56 100644 --- a/docs/IContractMetadataRegistry.md +++ b/docs/IContractMetadataRegistry.md @@ -18,7 +18,7 @@ function registerMetadata(address contractAddress, string metadataUri) external - +*Records `metadataUri` as metadata for the contract at `contractAddress`.* #### Parameters From 401b10d17ea4f23f7bfa6343b627253de92cba4e Mon Sep 17 00:00:00 2001 From: Krishang Nadgauda Date: Thu, 19 May 2022 23:33:10 -0400 Subject: [PATCH 14/16] run prettier --- contracts/ContractMetadataRegistry.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contracts/ContractMetadataRegistry.sol b/contracts/ContractMetadataRegistry.sol index caba81eda..135d8dcab 100644 --- a/contracts/ContractMetadataRegistry.sol +++ b/contracts/ContractMetadataRegistry.sol @@ -10,7 +10,6 @@ import "@openzeppelin/contracts/metatx/ERC2771Context.sol"; import { IContractMetadataRegistry } from "./interfaces/IContractMetadataRegistry.sol"; contract ContractMetadataRegistry is IContractMetadataRegistry, ERC2771Context, Multicall, AccessControlEnumerable { - /// @dev Only accounts with OPERATOR_ROLE can register metadata for contracts. bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); @@ -38,9 +37,9 @@ contract ContractMetadataRegistry is IContractMetadataRegistry, ERC2771Context, require(hasRole(OPERATOR_ROLE, _msgSender()), "Not operator."); require(bytes(metadataUri).length > 0, "No metadata"); require(bytes(getMetadataUri[contractAddress]).length == 0, "Metadata already registered"); - + getMetadataUri[contractAddress] = metadataUri; - + emit MetadataRegistered(contractAddress, metadataUri); } From ae656d9d0b276f571b0ba2d328197bc816c7f5db Mon Sep 17 00:00:00 2001 From: Krishang Nadgauda Date: Thu, 19 May 2022 23:38:53 -0400 Subject: [PATCH 15/16] cleanup script comments --- scripts/deploy/byocSetup.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/scripts/deploy/byocSetup.ts b/scripts/deploy/byocSetup.ts index f899f3100..6b88c8cc7 100644 --- a/scripts/deploy/byocSetup.ts +++ b/scripts/deploy/byocSetup.ts @@ -5,14 +5,14 @@ import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; import { TWRegistry, ContractMetadataRegistry, ContractDeployer, ContractPublisher } from "typechain"; /** - * NOTE: This deploy script is written for Polygon-Mumbai. * - * There is a mock `TWRegistry` deployed on Polygon-Mumbai for the purposes of Byoc testing. + * There is a mock `TWRegistry` deployed on testnets for the purposes of thirdweb deploy testing. * * This script does the following: - * (1) deploys `contracts/ByocRegistry` and `contracts/ByocFactory`. - * (2) grants `OPERATOR_ROLE` in `TWRegistry` to the deployed `ByocFactory`. - * (3) verifies deployed contracts. + * (1) deploys `contracts/ContractMetadataRegistry` and `contracts/ContractDeployer`. + * (2) grants `OPERATOR_ROLE` in `TWRegistry` to the deployed `ContractDeployer`. + * (3) grants `OPERATOR_ROLE` in `ContractMetadataRegistry` to the deployed `ContractDeployer`. + * (4) verifies deployed contracts. */ async function verify(address: string, args: any[]) { @@ -32,11 +32,8 @@ async function main() { const trustedForwarder: string = "0xc82BbE41f2cF04e3a8efA18F7032BDD7f6d98a81"; - // const registryAddress: string = ethers.constants.AddressZero; // replace - // const registry: TWRegistry = await ethers.getContractAt("TWRegistry", registryAddress); - const registry: TWRegistry = await ethers.getContractFactory("TWRegistry").then(f => f.deploy(trustedForwarder)); - console.log("\nDeploying new TWRegistry \ntx: ", registry.deployTransaction.hash, "\naddress: ", registry.address); - await registry.deployTransaction.wait(); + const registryAddress: string = ethers.constants.AddressZero; // REPLACE FOR CORRECT CHAIN + const registry: TWRegistry = await ethers.getContractAt("TWRegistry", registryAddress); const contractMetadataRegistry: ContractMetadataRegistry = await ethers .getContractFactory("ContractMetadataRegistry") From a603d4a61bb3636ede980f4ef53fed61e6afc883 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Fri, 20 May 2022 09:00:05 -0700 Subject: [PATCH 16/16] fix forge tests --- ...Registry.t.sol => ContractPublisher.t.sol} | 49 ++++++++++++------- src/test/utils/BaseTest.sol | 10 ++-- 2 files changed, 36 insertions(+), 23 deletions(-) rename src/test/{ByocRegistry.t.sol => ContractPublisher.t.sol} (83%) diff --git a/src/test/ByocRegistry.t.sol b/src/test/ContractPublisher.t.sol similarity index 83% rename from src/test/ByocRegistry.t.sol rename to src/test/ContractPublisher.t.sol index 410dd0315..73f43e6cc 100644 --- a/src/test/ByocRegistry.t.sol +++ b/src/test/ContractPublisher.t.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; // Target contracts -import { ByocRegistry } from "contracts/ByocRegistry.sol"; -import "contracts/interfaces/IByocRegistry.sol"; +import { ContractPublisher } from "contracts/ContractPublisher.sol"; +import "contracts/interfaces/IContractPublisher.sol"; import "contracts/TWRegistry.sol"; // Test helpers @@ -18,7 +18,7 @@ contract MockCustomContract { } } -contract IByocRegistryData { +contract IContractPublisherData { /// @dev Emitted when the registry is paused. event Paused(bool isPaused); @@ -29,7 +29,7 @@ contract IByocRegistryData { event ContractPublished( address indexed operator, address indexed publisher, - IByocRegistry.CustomContractInstance publishedContract + IContractPublisher.CustomContractInstance publishedContract ); /// @dev Emitted when a contract is unpublished. @@ -42,8 +42,8 @@ contract IByocRegistryData { event RemovedContractToPublicList(address indexed publisher, string indexed contractId); } -contract ByocRegistryTest is BaseTest, IByocRegistryData { - ByocRegistry internal byoc; +contract ContractPublisherTest is BaseTest, IContractPublisherData { + ContractPublisher internal byoc; TWRegistry internal twRegistry; address internal publisher; @@ -55,7 +55,7 @@ contract ByocRegistryTest is BaseTest, IByocRegistryData { function setUp() public override { super.setUp(); - byoc = ByocRegistry(byocRegistry); + byoc = ContractPublisher(contractPublisher); twRegistry = TWRegistry(registry); publisher = getActor(0); @@ -74,7 +74,10 @@ contract ByocRegistryTest is BaseTest, IByocRegistryData { contractId ); - IByocRegistry.CustomContractInstance memory customContract = byoc.getPublishedContract(publisher, contractId); + IContractPublisher.CustomContractInstance memory customContract = byoc.getPublishedContract( + publisher, + contractId + ); assertEq(customContract.contractId, contractId); assertEq(customContract.publishMetadataUri, publishMetadataUri); @@ -97,7 +100,10 @@ contract ByocRegistryTest is BaseTest, IByocRegistryData { contractId ); - IByocRegistry.CustomContractInstance memory customContract = byoc.getPublishedContract(publisher, contractId); + IContractPublisher.CustomContractInstance memory customContract = byoc.getPublishedContract( + publisher, + contractId + ); assertEq(customContract.contractId, contractId); assertEq(customContract.publishMetadataUri, publishMetadataUri); @@ -144,13 +150,14 @@ contract ByocRegistryTest is BaseTest, IByocRegistryData { vm.prank(publisher); byoc.approveOperator(operator, true); - IByocRegistry.CustomContractInstance memory expectedCustomContract = IByocRegistry.CustomContractInstance({ - contractId: contractId, - publishTimestamp: 100, - publishMetadataUri: publishMetadataUri, - bytecodeHash: keccak256(type(MockCustomContract).creationCode), - implementation: address(0) - }); + IContractPublisher.CustomContractInstance memory expectedCustomContract = IContractPublisher + .CustomContractInstance({ + contractId: contractId, + publishTimestamp: 100, + publishMetadataUri: publishMetadataUri, + bytecodeHash: keccak256(type(MockCustomContract).creationCode), + implementation: address(0) + }); vm.expectEmit(true, true, true, true); emit ContractPublished(operator, publisher, expectedCustomContract); @@ -181,7 +188,10 @@ contract ByocRegistryTest is BaseTest, IByocRegistryData { vm.prank(publisher); byoc.unpublishContract(publisher, contractId); - IByocRegistry.CustomContractInstance memory customContract = byoc.getPublishedContract(publisher, contractId); + IContractPublisher.CustomContractInstance memory customContract = byoc.getPublishedContract( + publisher, + contractId + ); assertEq(customContract.contractId, ""); assertEq(customContract.publishMetadataUri, ""); @@ -207,7 +217,10 @@ contract ByocRegistryTest is BaseTest, IByocRegistryData { vm.prank(operator); byoc.unpublishContract(publisher, contractId); - IByocRegistry.CustomContractInstance memory customContract = byoc.getPublishedContract(publisher, contractId); + IContractPublisher.CustomContractInstance memory customContract = byoc.getPublishedContract( + publisher, + contractId + ); assertEq(customContract.contractId, ""); assertEq(customContract.publishMetadataUri, ""); diff --git a/src/test/utils/BaseTest.sol b/src/test/utils/BaseTest.sol index 00ca7251c..57dea3534 100644 --- a/src/test/utils/BaseTest.sol +++ b/src/test/utils/BaseTest.sol @@ -24,8 +24,8 @@ import "contracts/token/TokenERC721.sol"; import "contracts/token/TokenERC1155.sol"; import "contracts/marketplace/Marketplace.sol"; import "contracts/vote/VoteERC20.sol"; -import { ByocRegistry } from "contracts/ByocRegistry.sol"; -import { ByocFactory } from "contracts/ByocFactory.sol"; +import { ContractPublisher } from "contracts/ContractPublisher.sol"; +import { ContractDeployer } from "contracts/ContractDeployer.sol"; import "contracts/mock/Mock.sol"; abstract contract BaseTest is DSTest, Test { @@ -43,7 +43,7 @@ abstract contract BaseTest is DSTest, Test { address public registry; address public factory; address public fee; - address public byocRegistry; + address public contractPublisher; address public factoryAdmin = address(0x10000); address public deployer = address(0x20000); @@ -66,9 +66,9 @@ abstract contract BaseTest is DSTest, Test { forwarder = address(new Forwarder()); registry = address(new TWRegistry(forwarder)); factory = address(new TWFactory(forwarder, registry)); - byocRegistry = address(new ByocRegistry(forwarder)); + contractPublisher = address(new ContractPublisher(forwarder)); TWRegistry(registry).grantRole(TWRegistry(registry).OPERATOR_ROLE(), factory); - TWRegistry(registry).grantRole(TWRegistry(registry).OPERATOR_ROLE(), byocRegistry); + TWRegistry(registry).grantRole(TWRegistry(registry).OPERATOR_ROLE(), contractPublisher); fee = address(new TWFee(forwarder, factory)); TWFactory(factory).addImplementation(address(new TokenERC20(fee))); TWFactory(factory).addImplementation(address(new TokenERC721(fee)));