@mattereum/assetpassport-smartcontract
v0.7.2
Published
On-chain code for commiting to claims and selling warranties.
Downloads
6
Readme
Mattereum Asset Passport Smart Contracts
This repository holds the smart contracts necessary to create Non-Fungible Tokens (NFTs) that act as key components of the Mattereum Asset Passports (MAP).
Index
Capabilities
Standard ERC-721 (NFT) Functionality
The Mattereum collection of NFT contracts (SimpleExchangeNFT.sol
, ReceiptNFT.sol
, and CidNFT.sol
) all inherit the basic functionality of an ERC-721 NFT. Additionally, for the inheritance from SimpleExchangeNFT.sol
to CidNFT.sol
, they specifically use the initializable version, ERC721Upgradeable.sol
by Open Zeppelin.
The Basic functionality of an ERC-721 NFT includes:
- Minting
- Safe minting (ensures receiving address can specifically receive ERC-721s, otherwise, reverts)
- Burning
- Setting approval
- Transfer
- Safe Transfer (ensures receiving address can specifically receive ERC-721s, otherwise, reverts)
- Obtain basic information about NFT (owner, balance, name, ID, tokenURI)
For SimpleExchangeNFT.sol
, it inherits from the ERC721Upgradeable.sol
version due to the design using Upgradeable Beacon Proxies to generate new Mattereum NFT collections in association with its Mattereum Asset Passports (MAP). The beacon proxies are created in NFTFactory.sol
.
Proxy Factory Pattern
The Proxy Factory Pattern is used in the NFTFactory.sol
contract in order to simply and cheaply call and create beacon proxy contracts, which point to an upgradeable Beacon contract. This upgradeable Beacon contract simply stores and retrieves the address of the original set of smart contracts first deployed, that are used as the basis for the implementation contract. In other words, an original set of the Mattereum collection of NFT contracts are first deployed, and then cloned for future NFT collections that are deployed. This greatly reduces gas cost for deployment of a full set of smart contracts associated with a MAP, which is quite necessary when running on the Ethereum network. Within NFTFactory.sol
, the function createNewCollection()
is used to generate the new set of cloned contracts. Using this setup also allows the ability to later upgrade the primary Beacon contract to point to a new implementation address, effectively allowing for bug fixes, new feature roll outs, etc. The ability to upgrade the master implementation contracts is secured by Open Zeppelin's Role Based Access Controls.
Pauseable Functionality
Several additional features have been included on top of the base ERC-721 contract; one of them to make the contract "pauseable". A pauseable contract has mechanisms to stop smart contract functionalities such as transfer or approval. The primary benefit of the pauseable token contract is safety. In case of any contract vulnerability which may be needed to update the contract, pausing can stop transfers and other core functionalities which reduces overall risk. This functionality is added in CidNFT.sol
.
It is important to properly handle access control when allowing additional features like pausing, burning, and locking by users other than the token owner, this is handled by "Role-Based Access Control (RBAC)". This is added in CidNFT.sol
.
Role-Based Access Control Functionality
Open Zeppelin provides a robust system to utilize RBAC through their AccessControl[Upgradeable].sol
contract. Additional information can be found in their documentation. In essence, we will be defining multiple roles, each allowed to perform different sets of actions. An account may have, for example, 'moderator', 'minter' or 'admin' roles, which you will then check for instead of simply using onlyOwner
. This check can be enforced through the onlyRole
modifier. Separately, you will be able to define rules for how accounts can be granted a role, have it revoked, and more.
Most software uses access control systems that are role-based: some users are regular users, some may be supervisors or managers, and a few will often have administrative privileges.
For the Mattereum set of smart contracts, the following Access Control Roles are used:
- DEFAULT_ADMIN_ROLE
- MINTER_ROLE
- BURNER_ROLE
- PAUSER_ROLE
- TOKEN_LOCK_ROLE
- HANDLE_USER
Currently, in the last deployment script in this repository, a script changes all of the Access Control roles above from the deployer
address to the Gnosis-Safe Mattereum Multisig
wallet address, and then revokes access to the deployer
address once complete.
Token Lock Functionality
The Token Lock functionality is very similar to token pausing ability, but is an in-house developed access control handled by a mapping array so that we can enable a locking feature on a "per token basis" rather than "per contract". It simply tracks each NFT's token ID and returns whether isTokenLocked[]
is true
or false
. It requires the TOKEN_LOCK_ROLE
discussed above to alter its state. This functionality is added in SimpleExchangeNFT.sol
.
Transfer Handler Functionality
The transfer handler functionality added in SimpleExchangeNFT.sol
was necessary to properly integrate and track secondary sales within the OpenSea NFT Marketplace. It is handled within the contracts in the /contracts/nft/handlers/
folder. Additionally, once certain checks pass, it also mints a simple NFT from the ReceiptNFT.sol
contract. This functionality may change in the future as new logic is created to integrate with OpenSea as well as other NFT Marketplaces.
Technical How-to
Installation
Clone the repository and set up the project with the following commands:
git clone [email protected]:mattereum-public/assetpassport-smartcontract.git
cd assetpassport-smartcontract
npm install
Deployment
Deployment is semi-automatic (and should be fully automatic!). The GitLab CI/CD pipeline has the following two steps that must currently be manually started:
- snapshot-deploy (deploy to testnet)
- mainnet-deploy (deploy to mainnet)
When deployment completes, it is necessary to note the address of the main proxy contract, which is used as the value of the --nftContractAddress
argument to map
.
To find this address, go to the pipeline for the job you just ran; if it’s not still open, start at the pipelines page and find the relevant pipeline run. Then in the logs search box, search for “collection proxy”. The address needed is that of the collection proxy.