Hashtag NFT Collective Documentation & Specification
Author | Ashley Turing |
Status | Initial Commit |
Created | 2021-12-27 |
Livetree’s Hashtag NFT Collective suite of 11 smart contracts are a result of many years of work to realise the ambition of decentralizing social networks. The ultimate goal is to empower creators to earn more and collectively address some of the world’s most challenging problems, from climate change, global inequality to empowering musicians, artists, activists and educators to escape the middlemen who restrict earnings and creativity. This repo contains the smart contracts that together define a #Collective. A collective can be thought of as a DAO with extended functionality specifically tailored to maximise income for creators and provide a fundamental paradigm shift in how social networks operate. Our hope by publishing these smart contracts interfaces openly is threefold:
- To enable creators to earn more through untapped Web 3.0 income streams, have direct collaborations with their collective’s members and to bring about positive social change
- To provide transparency, facilitate functional extensions, address any bugs or security concerns through the open-source community
- To eventually facilitate creators the ability to switch to different providers, such as, a different social network other than Livetree via their own decentralised wallet completely without intervention from Livetree. This empowers users and provides a new level of control over social posts and extends the earning capabilities of their social posts to be extended across potentially multiple social networks, as royalties for social posts can be accumulated from multiple websites into the same decentralised collective.
The smart contracts contain several innovations in their design and architecture and are detailed in the specification.
Technically the smart contracts address a number of functional “deficiencies” relating to NFTs (both 1155 and 741 standards, referred to as NFTs in this document) while remaining backward compatible. The smart contracts, which combined form the #Collective structure, have been designed to specifically try to address the following:
-
Royalty Treasury: NFTs today have no standard way to collect and pay out royalties. Some attempts have been made in the form of marketplace sales, however, existing standards only accommodate royalties to be paid for the sale of the NFT, provision for continual royalties to be paid along with flexibility to accommodate multiple royalty payout structures is notably missing e.g. to collect royalties from associated ticket sales, pay-per-view videos and so on. Building on extensive experience within the complex royalty structures of film and TV we realised that trying to enforce specific rules for royalties would not be sufficient, a more flexible approach is needed with a simple interface to support the deposit and payout with the ability to manage collections of royalties not only relating to NFTs but also wider creator potential income streams. For this reason, we have proposed a new EIP standard that facilitates the collection of royalties from a number of different sources. In its initial deployment this increases the earning capabilities for creators and extends earning capabilities to any number of social networks, NFT marketplaces or other websites. Eventually we foresee the treasury being flexible enough to accommodate a range of royalties from cinema tickets to merchandise sales.
-
Governance: once the treasury accumulates how it should be governed, this builds on standard DAO Openzepplin governor and adds extensions for specific proposal types.
-
Fractional Ownership: Being able to own a percentage stake of the Treasury and the underlying one or more NFT assets. The #Collective has 1 million membership ERC20 fungible tokens which implement IERC20Votable so they can be used for governance. These membership coins can also be redeemed against the Treasury, in which case they are destroy and the percentage share of the Treasury is paid out.
-
Unique Addressing NFT: In our case, each hashtag needs to be unique, however, much as with all other aspects of this EIP it can be used in many different ways. This is built on the Crypto-Naming-Service (CNS). Hash-tagging (#) media has become a defacto standard across Web 2.0 social networks for not only garnering support (e.g. #BLM, etc) but also more covert surveillance techniques. The introduction of a decentralised hashtag helps harness the power of media in a decentralised enables creators to earn from posts tagged with their #Collective’s name.
-
Machine learning support: specifically governance, viewing statistics and enhanced metadata
-
Legal License and creative copyright: Managing the complexity in legal and copyright licensing
-
Guild management: Although not in the initial deployment, eventually, we envision enabling assets to be lent out and re-claimed if and when certain conditions are met.
The #Collective smart contracts are defined as several interfaces that extend the ERC20 standard providing the functionality described above 7 points.
The design is to maximize the flexibility and resolve around the name of the collective.
-
[Step1] #Name Resolution
Resolves the name of the collective using the HashtagNFTCollectiveResolver.
By using the ResolveURI function of the HashtagNFTCollectiveResolver contract, you can get the collective’s ERC20 token(HashtagNFTCollectiveManager) address. -
[Step 2] Royalty Deposit Deposits royalties for a particular collective using the HashtagNFTCollectiveTreasury.
By using the DepositRoyalty function of the HashtagNFTCollectiveTreasury contract, you can deposit royalties for the collective(HashtagNFTCollectiveManager) - the address you’ve got on the [Step1]. -
[Step 3] Migration to another Social Network Owner of the collective would transfer ownership of the collective (collective’s contract) to Social Network X.
HashtagNFTCOllectiveManager, HashtagNFTCollectiveBuyInManager, HashtagNFTCollectiveERC721. -
[Step 4] Upgrade migrated collective’s contracts You can upgrade the contracts of the collective you’ve upgraded in the [Step 3].
# | Smart Contract | Description | Interacts with |
---|---|---|---|
1 | HashtagNFTCollectiveTreasury | The royalty manager for all collectives minted. It collates royalties paid to the projects & facilities royalty cashout for project stakeholders. |
HashtagNFTCollectiveManager: collates royalties paid into projects for stakeholders access. HashtagNFTCollectiveGovernor: provides interface for requestClaimRoyalty proposals, enabling withdrawal of royalties to vetted receiver’s address. |
2 | HashtagNFTCollectiveFactoryProxy | Factory for NFT & respective collectives. | HashtagNFTCollectiveManager: facilitates minting of collective tokens. HashtagNFTCollectiveBuyInManager: facilitates creation of buy-in offers. HashtagNFTCollectiveNFTVault: manages the collection’s NFTs. HashtagNFTCollectiveERC721: facilitates minting of new NFT assets. |
3 | HashtagNFTCollectiveBuyInManager | Manager that enables fractional ownership feature for NFT assets and collectives. | HashtagNFTCollectiveManager: represents the fractional ownership of the collective, being transferred between users through buy-in offer make/accept/refund. |
4 | HashtagNFTCollectiveManager | ERC20 token contract which represents the fractional ownership of the collective. | HashtagNFTCollectiveBuyInManager: facilitates the transferring collective tokens after buy-in offer is accepted. HashtagNFTCollectiveGovernor: provides the interface to set buy-out fee and to complete buy-out the collective. |
5 | HashtagNFTCollectiveNFTVault | ERC721Receivable contract which holds the collective’s NFT assets. | HashtagNFTCollectiveERC721: provides an interface to transfer a collective’s NFT to the marketplace through governor or collective owner. |
6 | HashtagNFTCollectiveGovernor | Provides DAO functionality for consensus on actions pertaining to the NFT project. | HashtagNFTCollectiveTreasury: provides interface to request royalty withdrawal to a specific address. HashtagNFTCollectiveManager: provides interface to request to set buy-out price of the collective and to complete buy-out the collective. HashtagNFTCollectiveERC721: provides interface to request to update the copyright license of the collective’s NFTs. HashtagNFTCollectiveNFTVault: provides interface to request to transfer NFT to the marketplace. |
7 | HashtagNFTCollectiveERC721 | NFT contract for holding assets & legal license data. | None |
8 | HashtagNFTCollectiveResolver | Provides Naming resolution functionality to retrieve HashtagNFTCollectiveManager information of HashtagNFTCollectiveERC721 | None |
9 | HashtagNFTCollectiveMarketplace | The smart contract used to trade the NFT assets. | HashtagNFTCollectiveERC721: facilitates the transferring the NFT to auction winner after the auction ends. HashtagNFTCollectiveTreasury: facilitates the depositing royalty to the NFT’s collective. |
# | Function | Input / Output | Description |
---|---|---|---|
1 | mint | Inputs MintCollectiveParams memory params(properties explained below) uint256 itemId - id of the NFT to be minted uint256 totalSupply - total supply of collective token uint256 listPrice - deprecated uint256 fee - deprecated string erc20TokenName - collective token’s name string erc20TokenSymbol - collective token’s symbol string erc20TokenLogoUrl - collective token’s logo url string nftMediaURL - NFT media URL string nftMetadataJsonUrl - NFT metadata JSON URL string nftViewStatsJsonUrl - NFT view stats JSON URL string nftPictureUrl - NFT picture URL string nftAppLinkUrl - App link to the NFT uint256 ownerInitialPercentage - deprecated uint256 buyerPercentage - deprecated string branchBuyerUsername - owner branch user name uint256 buyerItemId - deprecated string buyerOffer - deprecated Outputs uint256 - number of collectives minted by far emits Mint event |
Provides an interface for users to mint an NFT project & its corresponding collective token (HashtagNFTCollectiveManager), NFT (HashtagNFTCollectiveERC721), NFTVault (HashtagNFTColectiveNFTVault), BuyInManager (CollectiveNFTCollectiveBuyInManager). |
2 | mintForUser | Inputs MintCollectiveParams memory params string memory creator - creator branch user name Outputs none |
Provides an interface for backend server to mint an NFT project & related smart contracts on the behalf of the user. Uses mint function. Only backend service can call. |
3 | transferCollective | Inputs uint256 itemId - Index of the collective to transfer address newOwner - User address to be the owner of the collective Outputs none |
Transfer collective (minted by backend server) to the new owner. Only backend service call call. |
4 | mintNFT | Inputs MintItemParams calldata params(properties explained below) uint256 itemId - id of the NFT to be minted string erc20TokenName - ERC20 token name of the collective of the NFT to be minted in string erc20TokenSymbol - ERC20 token symbol of the collective for the NFT to be minted in string nftMetadataJsonUrl - NFT metadata JSON URL string nftViewStatsJsonUrl - NFT view stats JSON URL string nftPictureUrl - NFT Picture URL string nftAppLink - App link to the NFT Outputs none emits MintNFT event |
Provides an interface for the users to mint an NFT in the collective. |
5 | ImportExistingNfts | Inputs address[] calldata contracts - Addray of the existing NFT contracts to import uint256[] tokenIds - Ids of the existing NFTs to import Outputs uint256 - number of collectives minted by far |
Import existing NFTs by using NFT contract addresses and ids. |
6 | setContractAddresses | Inputs _address settings - settings logic address address manager - collective token logic address _address nftVault - NFTVault logic address address timelockController - timelock controller logic address _address governor - governor logic address Outputs none |
Sets the logic contract address of settings, collective token, nft vault, timelock controller, governor. Only owner can call. |
7 | setContractVersions | Inputs _uint256[] calldata contractVersions - array of the versions of the logic contracts Outputs none |
Sets the logic contract versions - settings, collective token, nft vault, timelock controller, governor. Only owner can call. |
8 | setGovernorSettings | Inputs _uint256 _votingPeriod - default voting period _uint256 _proposalThreshold - default proposal threshold _uint256 _nftDefaultLicenseURL - default copyright license URL for NFTs Outputs none |
Sets the governor settings (voting period, proposal threshold, default copyright license URL). Only owner can call. |
9 | userTokenExists (view) |
Inputs address user - user wallet address string memory name - collective token name string memory symbol - collective token symbol Outputs bool, uint256 - returns index in the user's NFT list, [true, index] if exists, [false, 0] if not exists. |
Check if the user owns the collective |
10 | setResolver | Inputs _address resolver - resolver contract address Outputs none |
Sets the resolver contract address. Only owner can call. |
11 | setSeedCToken | Inputs _address token - SEDC token address Outputs none |
Sets the SEDC token address. Only owner can call. |
12 | setAssetCount | Inputs uint256 count - NFT count of the collective uint256 itemId - NFT item id Outputs none |
Sets the NFT count of the collective where item exists. Only owner can call. |
13 | pauseCollective | Inputs _address manager - collective ERC20 token address _bool paused - true to pause, false to unpause |
Pause / Unpause a specific collective. Only owner can call. |
14 | isCollectivePaused |
Inputs _address manager - collective's ERC20 token address _uint256 version - latest contract version the collective should be _uint256 contractIndex - index of the logic contract(e.g. 0 for treasury) |
Returns false if the factory or collective is paused or contract needs to be upgraded. |
15 | pause | Inputs none Outputs none |
Pause the factory proxy contract. Only owner can call. |
16 | unpause | Inputs none Outputs none |
Unpause the factory proxy contract. Only owner can call. |
# | Function | Input / Output | Description |
---|---|---|---|
1 | setAutosaleSEDCSettings | Inputs _uint256 autoSaleRatioNumerator - collective token/SEDC conversion ratio numerator _uint256 autoSaleRatioDenominator - collective token/SEDC conversion ratio denominator _uint256 autoSaleLimit - Collective token amount that can be auto sold using SEDC token Outputs none |
Sets the SEDC auto sale conversion ratio and auto sale limit. Only collective curator can call. |
2 | makeBuyInOffer (payable) |
Inputs _string memory offerId - Buy-in offer id generated on the backend side _uint256 buyAmount - Collective token amount user wants to buy _uint256 offerAmount - native/SEDC/ERC20 token amount user offers _uint256 expiry - Buy-in offer’s expiry timestamp _uint256 offerToken - ERC20 token address user wants to pay, 0 for native Outputsnone emits MakeBuyInOffer event |
Provides interface to make an offer to buy-in collective tokens by using native token / ERC20 / SEDC token. Holds the offer token. The buy-in offer is automatically accepted by the collective owner and transfers collective tokens to the buyer if offer token is SEDC. |
3 | acceptBuyInOffer | Inputs _string memory offerId - Buy-in offer id to accept Outputs none emits AcceptBuyInOffer event |
Provides interface to accept a buy-in offer. Transfers the offer token to the seller(who accepted the buyin offer), transfers collective tokens from the seller to the buyer. |
4 | refundBuyInOffer | Inputs _string memory offerId - Buy-in offer id to withdraw Outputs none emits RefundBuyInOffer event |
Provides interface to withdraw an expired buy-in offer. Transfers the offer token back to the buyer. |
# | Function | Input / Output | Description |
---|---|---|---|
1 | mint | Inputs _uint256 supply - Number of collective tokens to mint Outputsnone |
Mints collective tokens for the curator of the collective. Only backend server wallet can call. |
2 | mintGovernor | Inputs none Outputs address - Governor contract address deployed |
Deploys the timelock controller and governor contracts for the collective. Only factory proxy contract can call. |
3 | transferCollectiveTokens | Inputs _address seller - Seller address of the buy-in offer (who accepted it) _address buyer - Buyer address of the buy-in offer(who made it) uint256 exchangeAmount - Number of the collective tokens to transfer Outputs none |
Transfers the exchange amount of collective tokens from buyer to seller. Only collective's buy-in manager contract can call. |
4 | setBuyOutAmount | Inputs uint256 amount - new buy-out fee Outputs none emits SetBuyOutAmount event |
Sets the buy-out fee of the collective. Only collective's governor contract can call. |
5 | buyOut (payapble) |
Inputs _address _buyer - address of the buyer Outputs none emits BuyOut event |
Buys out the collective - get the ownership of the collective, get the rights ownership of the NFTs. Instead deposts buy-out fee to the treasury. Only collective's governor contract can call. |
6 | transferOwnershipTo | Inputs _address newOwner - New owner’s address. Outputs none emits TransferOwnershipTo event |
Transfers all the collective tokens and the ownership of the collective and NFTs. Can be called only by backend server wallet or factory proxy contract. |
7 | treasuryBurnAmount | Inputs address burnAddress - Wallet address to burn collective tokens from uint256 amount - Collective token amount to burn Outputs none |
Burns the user's collective tokens after treasury cash-out. Only treasury contract can call. |
8 | setBuyInManager | Inputs _address buyinManager - Buy-in manager contract address |
Sets the buy-in manager contract address of the collective after mint. Only factory proxy can call. |
# | Function | Input / Output | Description |
---|---|---|---|
1 | requestClaimRoyalty | Inputs address receiver - User address to transfer royalty to uint256 amount - Royalty amount to transfer string calldata description - Proposal description Outputs uint256 - proposal Id created |
Creates a proposal to withdraw royalty amount to the receiver |
2 | requestSetBuyOutPrice | Inputs uint256 amount - New buy-out price to propose string calldata description - Proposal description Outputs uint256 - proposal Id created |
Creates a proposal to set the buy-out price of the collective |
3 | requestSetLicense | Inputs string calldata licenseURI - new license file URL string calldata description - Proposal description Outputs uint256 - proposal Id created |
Creates a proposal to set the copyright license of the NFTs in the collective. |
4 | requestBuyOut (payable) |
Inputs int256 buyoutFee - buyout price buyer willing to pay string calldata description - Proposal description Outputs uint256 - proposal Id created |
Creates a proposal to buy-out the collective. |
5 | requestSetProposalThreshold | Inputs uint256 newProposalThreshold - new proposal threshold to propose string calldata description - Proposal description Outputs uint256 - proposal Id created |
Creates a proposal to set the proposal of the collective governor. |
6 | requestUpdateQuorumNumerator | Inputs uint256 newQuorumNumerator - new voting quorum numerator proposed string calldata description: Proposal description Outputs uint256 - proposal Id created |
Creates a proposal to set the voting quorum numerator of the collective governor. |
7 | requestNFTSale | Inputs address nftAddress - NFT contract address to set for sale uint256 itemId - NFT item id to set for sale string calldata description - Proposal description Outputsuint256 proposal Id created |
Creates a proposal to set the NFT for sale |
8 | refundBuyoutFee | Inputs uint256 proposalId - Id of the buy-out proposal Outputs none |
Refund the buy-out fee used to make a buy-out proposal. |
# | Function | Input / Output | Description |
---|---|---|---|
1 | createCollectible | Inputs _string memory mediaURL - media URL uint256 itemId - NFT item Id string memory metadataJsonUrl string memory viewStatJsonUrl string memory picUrl string memory appLinkUrl string memory defaultLicenseURL Outputs uint256 - minted NFT Id |
Mints an NFT with given arguments. |
2 | wrapToken | Inputs address from - owner address uint256 tokenId - NFT Id Outputs uint256 - minted NFT Id |
Wrap an existing NFT - mint a new NFT from the existing one and transfer the existing NFT to the NFT contract. |
3 | unwrapToken | Inputs uint256 tokenId - NFT Id to unwrap Outputs Unwrap an imported NFT - burn the NFT and transfer the imported NFT to the NFT vault. Only NFT vault contract can call. |
|
4 | setWrappedTokenURI | Inputs address from - deprecated _uint256tokenId: NFT item Id |
Set the tokenURI of the NFT. |
5 | setRoyalties | Inputs uint256[] memory tokenIds - Array of NFT item Id uint256 royalties - Array of the royalties for each NFT item Outputs none |
Set the royalties for NFT items |
6 | royaltyInfo (view) |
Inputs _uint256 tokenId - NFT item Id _uint256 salePrice - NFT sale price Get the royalty payment information of the NFT item. |
|
7 | setRightsOwner | Inputs _address rightsOwner - rights owner address to be set Outputs none |
Set the rights ower of the NFT contract, rights owner is the receiver of the royalties. |
8 | getRightsOwner (view) |
Inputs Outputs address - rights owner address |
Retrieves the rights owner of the NFT contract. |
9 | setLicense | Inputs string memory url - new license file URL Outputs none |
Sets the copyright license of the NFT contract. |
10 | getLicenseInfo (view) |
Inputs none Outputs string[] - current license info(URL and timestamp) string[]][] license history |
Retrieves the current copyright license and the history. |
11 | setManager | Inputs _address manager - collective token contract address Outputs none |
Sets the collective token contract address. |
12 | setNFTVault | Inputs _address nftVault - collective NFT vault contract address Outputs none |
Sets the collective's NFT vault contract address. |
13 | setGovernor | Inputs _address governor - collective governorcontract address Outputs none |
Sets the collective's governor address. |
# | Function | Input / Output | Description |
---|---|---|---|
1 | startNFTAuction | Inputs _address nftAddress - NFT contract address for auction _uint256 itemId - NFT item id for auction _uint256 proposalId - proposal Id - 0 if not through the collective's governor Outputs uint256 - auction id created emits StartNFTAuction event |
Initiate an auction for the NFT. |
2 | endNFTAuction | Inputs _uint256 auctionId - auction id to end _AuctionState closingState - either ClosedNoWinner or ClosedWithWinner _uint256 _winner bid id Outputs none emits EndNFTAuction event |
Ends the NFT auction. |
3 | auctionState (view) |
Inputs _uint256 auctionId - auction id to end Outputs AuctionState - state of the auction |
Returns the state of the auction. |
4 | placeBid (payable) |
Inputs _uint256 auctionId - Id of the auction to place bid on _address bidToken - bid token address _uint256 bidAmount - amount of the bid token Outputs none emits PlaceBid event |
Provides an interface to place a bid to the auction. |
5 | auctionBidCount (view) |
Inputs _uint256 auctionId - auction Id Outputs uint256 - number of bids on the auction |
Retrieves the number of bids on the NFT auction. |
6 | auctionBidList (view) |
Inputs _uint256 auctionId - auction Id Outputs AuctionBid[] - list of the bids on the auction |
Retrieves the list of bids on the NFT auction |
7 | refundBid | Inputs _uint256 auctionId - auction Id _uint256 bidId - Id of the bid to refund Outputs none emits RefundBid event |
Provides an interface to refund the bid. |
8 | transferNFTToWinner | Inputs _uint256 auctionId: auction Id _uint256 bidId - win bid Id _address winner - auction winner address to transfer the NFT Outputs none emits TransferNFTToWinner event |
Provides an interface to transfer the NFT to the auction winner. |