# RIF Marketplace Specification ## Marketplace roles There are different roles in the marketplace. Each role can perform specific actions into the system. The roles can be managed by the owner of the marketplace. ### Owner The marketplace owner is able to perform any action into the marketplace. Ideally this will be handled by a multisig or to a governance token. ### Administrator The administrator is able to perform the following tasks: - Change marketplace configuration parameters - Whitelist other roles in the system ### Asset Manager The asset Manager take place when the markeplace has the parameter requireWhitelistedAsset in true. This role is in charge of approving or removing accepted assets types into the marketplace. It is the role that manage the accepted token whitelisting. ### Asset Validator Manager This role takes place when the configuration parameter assetsNeedValidation is true. This role is in charge of managing the whitelist of validators in the system. ### Finance Manager Anything related to cryptocurrencies, payments, withdraw, fees should be handle it by this role. - Change finance parameters (fees for example) - Withdraw money earned by fees ### Asset Providers Manager This roles takes place when the configuration parameter requireWhitelistedAssetProvider is in true. In this case this role is in charge of managing the whitelist of assets providers. ### Asset Validator Delegate Sometimes the assets validators can be institutions (for example an art gallery for a ecommerce of art NFT). Probably this institutions will have a group of persons in charge of make the validating of the assets (for example if an art piece is really unique and is created with the minimum quality required by the marketplace). This is the role who will manage this delegates. Any asset validator delegate will have to be assigned to one asset validator at minimum. But a delegate can work for many validators (for example an art critic can work to many museums or art galleries). ## Marketplace configuration parameters #### Require whitelisted asset | Name | Type | | -------- | -------- | | SCHEDULER_ADDRESS | Boolean | Defines whether the marketplace will require the asset type to be whitelisted before the asset can be registered. - **IF TRUE:** the marketplace will accept any asset from any source (contract address). For example in the case of NFTs it will accept any ERC721 or ERC1155 without restriction to the contract address. - **IF FALSE:** only whitelisted tokens could be listed in the marketplace #### Require whitelisted asset provider | Name | Type | | -------- | -------- | | requireWhitelistedAssetProvider | Boolean | We should be able to create marketplaces where anyone can list their assets into that marketplace (example opensea), or marketplaces were the assets providers (the accounts who put items to sell) are whitelisted or restricted to some accounts (for example if we want to create a marketplace to sell just specific products) - **IF TRUE:** the providers of assets will have to be whitelisted before registering assets - **IF FALSE:** any account will be able to register assets for sale into the marketplace. #### Assets needs validation/approval before been accepted into the marketplace | Name | Type | | -------- | -------- | | assetsNeedValidation | Boolean | There will be some marketplaces were the content listed for sale will need some validation or curation process. The owner of the marketplace should be able to setup this aspect. - **IF TRUE:** an asset can be registered but it can't be placed on sell until is approved. The validators (the role who can validate an assets) are whitelisted accounts. - **IF FALSE:** any provider can put any asset on sale without any validation and/or approval #### All assets uses the same sale strategy | Name | Type | | -------- | -------- | | allAssetsUsesSameSaleStrategy | Boolean | The markeplace will have one or multiple sale strategies (like fixed price, auction, etc.). The marketplace admins will be able to register multiple supported sale strategies. - **IF TRUE:** all the assets will accepts the same strategi(es). - **IF FALSE:** the provider should select which strategy to use on his asset (from the avaiable ones) #### All assets accepts the same currencies | Name | Type | | -------- | -------- | | allAssetsAcceptsSameCurrencias | Boolean | We will develop the marketplace to accept any ERC20 token. But marketplace owners can define which are the tokens they want to accepto in their marketplaces (like RIF, RDOC, etc.). - **IF TRUE:** all the accepts into the marketplace will accept the same currencies (the ones the owner of the Marketplace defined) - **IF FALSE:** the asset provider can select which currencies accept for their asset(s). #### Create a RNS subdomain for each asset | Name | Type | | -------- | -------- | | createSubdomainForEachAsset | Boolean | In order to increase usability it may be worth to associate a RNS subdomain to each asset listed on the marketplace. - **IF TRUE:** Each asset registered on the markeplace will have a subdomain associated. - **IF FALSE:** No subdomain will be associated with the listed assets. #### Supports staking and slashing | Name | Type | | -------- | -------- | | supportsStakingAndSlashing | Boolean | - **IF TRUE:** The providers may need to make staking in order to provide services/assets - **IF FALSE:** staking is not required in any place of the marketplace We will not implement the staking and slashing mechanisms on the MVP ## Features/Stories ### As a Markeplace owner I want to deploy the marketplace smart contracts for my own marketplace instance Deploy a new instance of the marketplace should be straight forward to any project. The marketplace should be fully parametrizable. ```sequence Marketplace Owner->Blockchain: constructor(params) Blockchain-->Marketplace Owner: ``` | Param Name | Type | Description | | ---------- | --- | ---- | | requireWhitelistedAsset | boolean | See section: Marketplace configuration parameters | |requireWhitelistedAssetProvider|boolean| See section: Marketplace configuration parameters | |assetsNeedValidation|boolean| See section: Marketplace configuration parameters | |allAssetsUsesSameSaleStrategy| boolean | See section: Marketplace configuration parameters | |allAssetsAcceptsSameCurrencies| boolean | See section: Marketplace configuration parameters | |createSubdomainForEachAsset | boolean | See section: Marketplace configuration parameters | |supportsStakingAndSlashing | boolean | See section: Marketplace configuration parameters | ### As a Marketplace owner I want to manage the list of authorized system administrators The marketplace owner should be able to add and remove the administrators on the system. The ONLY allowed to manage this is the marketplace owner account. ### As a Marketplace administrator I want to manage the asset managers whitelist ### As a Marketplace administrator I want to manage the asset validator managers whitelist ### As a Marketplace owner I want to manage the finance role whitelist ### As a Marketplace administrator I want to manage the asset provider manager whitelist ### As a Marketplace administrator I want to manage the asset validator delegate whitelist ### As a Marketplace administrator I want to manage the configuration properties of the marketplace The administrator will be able to change the parameters of the marketplace in any momment. Please see the section "Marketplace configuration parameters", for more information about the different configuration properties. ### As a finance manager I want to add an ERC20 token as a payment currency into the marketplace The finance rol should be able to add new ERC20 tokens as accepted tokens into the marketplace. ```sequence Finance Rol->IMarketplace: addAcceptedCurrency(address _tokenERC20) IMarketplace->IMarketplace: check if address is ERC20 IMarketplace->ERC20 Token: name() ERC20 Token-->IMarketplace: IMarketplace->ERC20 Token: symbol() ERC20 Token-->IMarketplace: IMarketplace->ERC20 Token: decimals() ERC20 Token-->IMarketplace: IMarketplace->IMarketplace: create accepted currency struct IMarketplace->IMarketplace: add accepted currency struct into contract state IMarketplace-->Finance Rol: ``` ### As a finance manager I want to remove an ERC20 token as a payment currency into the marketplace The finance rol should be able to remove an ERC20 token as accepted token into the marketplace. This could be a costly action in terms of gas, because it will need to remove an item from a list. ```sequence Finance Rol->IMarketplace: removeAcceptedCurrency(address _tokenERC20) IMarketplace->IMarketplace: remove currency struct from contract state IMarketplace-->Finance Rol: ``` ### As a finance manager I want to withdraw contract funds to an account The financial manager should be able to withdraw the funds of the contract (collected form marketplace fees) to any account he wants. ```sequence Finance Rol->IMarketplace: withdraw(address _to, int amount) IMarketplace->IMarketplace: check if the contract has enough balance IMarketplace->IMarketplace: to account must be different of null IMarketplace->IMarketplace: transfer funds IMarketplace-->Finance Rol: ``` ### As an asset validator I want to add an asset validator delegate The asset validators can have multiple accounts who can validate assets in their name. The use case could be an art gallery who has multiple art experts working for them in order to validate the work. An asset validator delegate can work for multiple asset validators (for example an art expert can work for multiple art galleries). We should evaluate to associate the asset validators delegates to a DID and generate reputation to this (same to validator delegate). ```sequence AssetValidator->IMarketplace: addAssetValidatorDelegate(address _account) IMarketplace->IMarketplace: check if asset validator exists in the marketplace IMarketplace->IMarketplace: check if _account is not null IMarketplace->IMarketplace: add asset validator delegate IMarketplace-->AssetValidator: ``` ### As an asset validator I want to remove an asset validator delegate from my allowed delegate list Remove asset validator delegate from the list of allowed delegates A valid use case could be an art gallery removing an art expert from his list of allowed validators. ```sequence AssetValidator->IMarketplace: removeAssetValidatorDelegate(address _account) IMarketplace->IMarketplace: check if asset validator exists in the marketplace IMarketplace->IMarketplace: check if the delegate is part of the validator whitelist IMarketplace->IMarketplace: remove asset validator delegate from asset validator whitelist IMarketplace-->AssetValidator: ``` ### As an administrator I want to assign a RNS domain or subdomain to the marketplace contract in order to create subdomains for assets The markeplace can create subdomains on a RNS domain to all the registered assets. This can be usefull for user experience. ```sequence Administrator->RNS: transfer domain to Marketplace instance RNS-->Administrator: Administrator->IMarketplace: assignRnsDomain(_rnsDomain) void IMarketplace-->Administrator: ``` ### As an administrator I want to add a RNS name generation strategy When the marketplace has active the flag createSubdomainForEachAsset it needs to generate a subdomain name for each asset registered in the system. For this we will have the name generation strategy. This strategy basically takes an asset as a parameter and returns the name to be used in RNS. ### As an asset provider I want to register a new asset into the marketplace We have to design the marketplace to support any type of asset, but for the sake of the MVP we will focus on NFTs. ```mermaid flowchart TD A[Asset Provider try to register a new asset] --> B{Mkp allows any type of assets?} B --> |No| C{The asset is in the whitelist?} C --> |No| D[Error] B --> |Yes| E{Mkp allows any provider?} C --> |Yes| E E --> |No| F{Provider is in the whitelist?} F --> |No| D E --> |Yes| G{Asset requires validator?} F --> |Yes| G G --> |Yes| H[Asset is moved to pending validation] H --> I{Validator approves asset?} J[Asset Validator] -- feedback --> I I --> |No| K[Asset Rejected] G --> |No| L[Asset Ready] I --> |Yes| L J -- new validator feedback --> M{valiator approves asset?} K --> M M --> |No| K M --> |Yes| L L --> N{Must create RNS subdomain?} N --> |Yes| O[Call strategy to get name] N --> |No| Z O --> P[Call RNS and create subdomain] P --> Q[Update asset with subdomain] Q --> Z[Finish] ``` ### As an asset validator delegate I want to approve an asset A validator delegate can approves assets that requires validation. This approval is made in name of a asset validator. The delegates can work for more than one validator, for that reason the delegate must provide in name of which validator he is working. ### As an asset validator delegate I want to reject an asset A validator delegate can rejects assets that requires validation. This rejection is made in name of a asset validator. The delegates can work for more than one validator, for that reason the delegate must provide in name of which validator he is working. ### As an asset provider I want to sell my asset ```mermaid flowchart TD AssetProvider[Asset Provider initiate asset sell process] AssetProvider --> AssetReady?{Asset is in state ready?} AssetReady? --> |No| Error AssetReady? --> |Yes| ProviderIsOwner?{Provider is owner of the asset?} ProviderIsOwner? --> |No| Error ProviderIsOwner? --> |Yes| AllAssetsUseSameSS?{All Assets use same sale strategy?} AllAssetsUseSameSS? --> |Yes| GetSaleStrategy[Get sale strategy for the marketplace] AllAssetsUseSameSS? --> |No| AssetProviderSelectSS[Asset Provider Select the strategy] GetSaleStrategy --> AllAssetsUseSameCurr?{All assets accepts the same currency?} AssetProviderSelectSS --> AllAssetsUseSameCurr? AllAssetsUseSameCurr? --> |Yes| GetAvailableCurr[Get currencies in marketplace] AllAssetsUseSameCurr? --> |No| AssetProviderSelectCurr[Asset provider select the currencies to be used] AssetProviderSetupPrices[Asset provider setup prices for each currency] GetAvailableCurr --> AssetProviderSetupPrices AssetProviderSelectCurr --> AssetProviderSetupPrices AssetProviderSetupPrices --> EscrowSetup[Escrow instance is created and setup with all the sale parameters] EscrowSetup --> AssetTransfer[The asset is transfered to the escrow] AssetTransfer --> OrderIdGeneration[Order Id generator strategy is called to generate a new order id] OrderIdGeneration --> OrderCreation[An order is created with status open] OrderCreation --> SaleStartsInmediatly?{Sale strategy starts inmediatly?} SaleStartsInmediatly? --> |Yes| OrderActive[Order pass to active state] OrderActive --> End SaleStartsInmediatly? --> |No| End ``` ### As an administrator I want to set an order id generation strategy for orders creation Everytime an order is created we need to generate a new order id, this order id must be unique across all the system. ## Design ### Class Diagram ```mermaid classDiagram class AssetApprovalRejectionRecord { } <<struct>> AssetApprovalRejectionRecord class Asset { -List~AssetApprovalRejectionRecord~ validatorHistory } class RNSResolver { } class NFTTokenResolver { -address tokenAddress -String tokenId } RNSResolver <|-- NFTTokenResolver class AssetValidator { -String name -address account -List~address~ delegates +constructor(String _name, address _account) +name() String +account() address +delegates() List~address~ } <<struct>> AssetValidator class IMarketplace { +addAcceptedCurrency(address _tokenERC20) void +removeAcceptedCurrency(address _tokenERC20) void +withdraw(address _to, int amount) void +addAssetValidatorDelegate(address _account) void +removeAssetValidatorDelegate(address _account) void +assignRnsDomain(RNSDomain _rnsDomain) void +assignRnsNameGenerationStrategy(address _strategy) void +registerAsset(Asset _asset) void +validatorDelegateApprovesAsset(Validator, Asset) void +validatorDelegateRejectAsset(Validator, Asset) void +assignOrderIdGeneratorStrategy(address _strategy) void +sellAsset(Asset _asset) int } <<Interface>> IMarketplace class IMarketplaceConfiguration { +changeAllowAnyAssetConfig(bool _newValue) void +changeAllowAnyAssetProviderConfig(bool _newValue) void +changeAssetsNeedValidationConfig(bool _newValue) void +changeAllAssetsUsesSameSaleStrategyConfig(bool _newValue) void +changeAllAssetsAcceptsSameCurrenciesConfig(bool _newValue) void +changeCreateSubdomainForEachAssetConfig(bool _newValue) void +changeSupportsStakingSlashing(bool _newValue) void } <<Interface>> IMarketplaceConfiguration IMarketplaceConfiguration <|-- RIFMarketplace class IMarketplaceAccessControl { +addAdministrator(address _adminAddr) void +removeAdministrator(address _adminAddr) void +addAssetManager(address _assetManagerAddr) void +removeAssetManager(address _assetManagerAddr) void +addAssetValidatorManager(address _assetValidatorManagerAddr) void +removeAssetValidatorManager(address _assetValidatorManagerAddr) void +addFinance(address _financeAddr) void +removeFinance(address _financeAddr) void +addAssetProviderManager(address _assetProviderManager) void +removeAssetProviderManager(address _assetProviderManager) void +addAssetValidatorDelegate(address _assetValidatorDelegate) void +removeAssetValidatorDelegate(address _assetValidatorDelegate) void } <<Interface>> IMarketplaceAccessControl IMarketplaceAccessControl <|-- RIFMarketplace class Ownable <<OpenZeppelin>> Ownable Ownable <|-- RIFMarketplace class AccessControl <<OpenZeppelin>> AccessControl AccessControl <|-- RIFMarketplace class MarketplaceAcceptedCurrency { -String name -String symbol -int decimals +constructor(String name, String symbol, int decimals) void +getName() String +getSymbol() String +getDecimals() int } <<struct>> MarketplaceAcceptedCurrency class RNSNameGenerationStrategy { +generate(Asset _asset) String } <<interface>> RNSNameGenerationStrategy class NFTRNSNameGenerationStrategy { } RNSNameGenerationStrategy <|-- NFTRNSNameGenerationStrategy class OrderIdGenerationStrategy { +generate(Asset _asset) int } <<interface>> OrderIdGenerationStrategy class Order { int orderId enum status address escrow int blockNumber } <<struct>> Order class RIFMarketplace { -bool requireWhitelistedAsset -bool requireWhitelistedAssetProvider -bool assetsNeedValidation -bool allAssetsUsesSameSaleStrategy -bool allAssetsAcceptsSameCurrencies -bool createSubdomainForEachAsset -bool supportsStakingSlashing -List~MarketplaceAccceptedCurrency~ acceptedCurrencies -List~AssetValidator~ assetValidators -RNSDomain rnsDomain -RNSNameGenerationStrategy rnsNameGenerationStrategy -OrderIdGenerationStrategy orderIdGenerationStrategy -Map~Order~ orders +constructor(bool _requireWhitelistedAsset, bool _requireWhitelistedAssetProvider, _assetsNeedValidation, bool _allAssetsUsesSameSaleStrategy, bool _allAssetsAcceptsSameCurrencies, bool _createSubdomainForEachAsset) void } IMarketplace <|-- RIFMarketplace ```