# SDK Interfaces Design
## IMarketplace
### Administrator
*(notes): Consider using get/set nomenclature*
## Proposal 1
```typescript=
interface IAccessControl {
addAdministrator(address: string) : Promise<boolean>;
removeAdministrator(address: string) : Promise<boolean>;
addAssetManager(address : string) : Promise<boolean>;
removeAssetManager(address : string) : Promise<boolean>;
addAssetValidatorManager(address: string) : Promise<boolean>;
removeAssetValidatorManager(address : string) : Promise<boolean>;
addAssetValidator(address: string) : Promise<boolean>;
removeAssetValidator(address: string) : Promise<boolean>;
addFinance(address: string) : Promise<boolean>;
removeFinance(address: string) : Promise<boolean>;
addFinanceManager(address: string) : Promise<boolean>;
removeFinanceManager(address: string) : Promise<boolean>;
addAssetProviderManager(address: string) : Promise<boolean>;
removeAssetProviderManager(address: string) : Promise<boolean>;
addAssetProvider(address: string) : Promise<boolean>;
removeAssetProvider(address: string) : Promise<boolean>;
}
/* Probably we need to segregate interfaces here */
interface IMarketplace {
changeRequireWhitelistedAsset(requireWhitelistedAsset: boolean) : Promise<boolean>;
changeRequireWhitelistedAssetProvider(requireWhitelistedAssetProvider: boolean) : Promise<boolean>;
changeRequireAssetValidation(requireAssetValidation: boolean) : Promise<boolean>;
changeRequireSaleStrategyPerAsset(requireSaleStrategyPerAsset: boolean) : Promise<boolean>;
changeRequireSameCurrencyPerAsset(requireSameCurrencyPerAsset: boolean) : Promise<boolean>;
changeRequireAssetSubdomain(requireAssetSubdomain: boolean) : Promise<boolean>;
changeSupportsStakingSlashing(supportStakingSlashing: boolean) : Promise<boolean>;
whitelistAsset(address: string) : Promise<boolean>;
removeAssetFromWhitelist(address: string) : Promise<boolean>;
isWhitelistedAsset(address: string) : Promise<boolean>;
addAcceptedCurrency(tokenERC20: string) : Promise<boolean>;
removeAcceptedCurrency(tokenERC20: string) : Promise<boolean>;
withdraw(to: string, amount: number) : Promise<boolean>;
addAssetValidatorDelegate(account: string) : Promise<boolean>;
removeAssetValidatorDelegate(account: string) : Promise<boolean>;
assignRnsDomain(rnsDomainNode: string) : Promise<boolean>;
assignRnsNameGenerationStrategy(strategy: string) : Promise<boolean>;
//registerAsset(Asset _asset) external;
validatorDelegateApprovesAsset(assetValidator: string, asset: string) : Promise<boolean>;
validatorDelegateRejectAsset(assetValidator: string, asset: string): Promise<boolean>;
assignOrderIdGeneratorStrategy(strategy: string) : Promise<boolean>;
sellAsset(asset: string) : Promise<boolean>;
}
interface IWhitelist {
add(address: string) : Promise<boolean>;
remove(address: string) : Promise<boolean>;
isWhitelisted(address: string) : Promise<boolean>;
}
class AssetWhitelist implements IWhitelist {
add(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
remove(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
isWhitelisted(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
}
/* We need to work on the interfaces for the smart contract interaction
Hint: Look into legacy marketplace-ui contract
- https://github.com/rsksmart/rif-marketplace-ui/blob/develop/src/contracts/wrappers/contract-base.ts
*/
abstract class ContractWrapper { }
class MarketplaceContractWrapper extends ContractWrapper {
constructor () {
super();
}
}
/* TODO : Add Asset Validator Delegate | RNS parts */
class Marketplace implements IMarketplace, IAccessControl {
private requireWhitelistedAsset! : boolean;
private requireWhitelistedAssetProvider! : boolean;
private requireAssetValidation! : boolean;
private requireSaleStrategyPerAsset! : boolean;
private requireSameCurrencyPerAsset! : boolean;
private requireAssetSubdomain! : boolean;
private supportsStakingSlashing! : boolean;
private assetWhitelist! : AssetWhitelist;
private contractWrapper : MarketplaceContractWrapper; // library to interact with contract (ethers);
[index: string] : any;
constructor (config: any = { }) {
Object.keys(config).forEach((key: string) => this[key] = config[key]);
this.assetWhitelist = new AssetWhitelist();
this.contractWrapper = new MarketplaceContractWrapper();
}
whitelistAsset(address: string) : Promise<boolean> {
return this.assetWhitelist.add(address);
}
removeAssetFromWhitelist(address: string) : Promise<boolean> {
return this.assetWhitelist.remove(address);
}
isWhitelistedAsset(address: string) : Promise<boolean> {
return this.assetWhitelist.isWhitelisted(address);
}
changeRequireWhitelistedAsset(requireWhitelistedAsset: boolean): Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
changeRequireWhitelistedAssetProvider(requireWhitelistedAssetProvider: boolean) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
changeRequireAssetValidation(requireAssetValidation: boolean) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
changeRequireSaleStrategyPerAsset(requireSaleStrategyPerAsset: boolean) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
changeRequireSameCurrencyPerAsset(requireSameCurrencyPerAsset: boolean) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
changeRequireAssetSubdomain(requireAssetSubdomain: boolean) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
changeSupportsStakingSlashing(supportStakingSlashing: boolean) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
addAdministrator(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
removeAdministrator(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
addAssetManager(address : string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
removeAssetManager(address : string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
addAssetValidatorManager(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
removeAssetValidatorManager(address : string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
addAssetValidator(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
removeAssetValidator(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
addFinance(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
removeFinance(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
addFinanceManager(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
removeFinanceManager(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
addAssetProviderManager(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
removeAssetProviderManager(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
addAssetProvider(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
removeAssetProvider(address: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
addAcceptedCurrency(tokenERC20: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
removeAcceptedCurrency(tokenERC20: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
withdraw(to: string, amount: number) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
addAssetValidatorDelegate(account: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
removeAssetValidatorDelegate(account: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
assignRnsDomain(rnsDomainNode: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
assignRnsNameGenerationStrategy(strategy: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
//registerAsset(Asset _asset) external;
validatorDelegateApprovesAsset(assetValidator: string, asset: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
validatorDelegateRejectAsset(assetValidator: string, asset: string): Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
assignOrderIdGeneratorStrategy(strategy: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
sellAsset(asset: string) : Promise<boolean> {
// TODO: Implement method
return Promise.resolve(true);
}
}
```
## Proposal 2
```typescript=
interface AccessControlable {
addAdministrator(_adminAddr: string);
removeAdministrator(_adminAddr: string);
addAssetManager(_assetManagerAddr: string);
removeAssetManager(_assetManagerAddr: string);
addAssetValidatorManager(_assetValidatorManagerAddr: string)
removeAssetValidatorManager(_assetValidatorAddr: string) ;
addAssetValidator(_assetValidatorManagerAddr: string);
removeAssetValidator(_assetValidatorAddr: string);
addFinance(_financeAddr: string);
removeFinance(_financeAddr: string);
addFinanceManager(_financeManagerAddr: string);
removeFinanceManager(_financeManagerAddr: string);
addAssetProviderManager(_assetProviderManagerAddr: string);
removeAssetProviderManager(_assetProviderManagerAddr: string);
addAssetProvider(_assetProviderAddr: string);
removeAssetProvider(_assetProviderAddr: string);
}
interface Configurable {
changeRequireWhitelistedAsset(boolean);
changeRequireWhitelistedAssetProvider(boolean);
changeRequireAssetValidation(boolean);
changeRequireSaleStrategyPerAsset(boolean);
changeRequireSameCurrencyPerAsset(boolean);
changeRequireAssetSubdomain(boolean);
changeSupportsStakingSlashing(boolean);
}
/**
* Represents a user who interacts with the contract
*/
abstract class User {
marketplace: MarketplaceContract; // web3/ethers contract instance
address: string;
constructor(marketplace: MarketplaceContract) {
this.marketplace = marketplace;
};
abstract getAddress(): string;
}
/**
* Abstract Role access
*/
interface AccessController {
add(): Promise<any>;
remove(): Promise<any>;
}
/*
* Concrete Roles Access in the marketplace
*/
class AssetManagerController extends User implements AccessController {
constructor(address: string, contract: ContractWrapper) {
super(contract);
this.address = address;
};
async add() {
this.marketplace.addAssetManager(this.getAddress());
};
async remove(){
this.marketplace.addAssetManager(this.getAddress());
};
getAddress() { return this.address }
}
class FinanceManagerController extends User implements AccessController {
constructor(address: string, contract: ContractWrapper) {
super(contract);
this.address = address;
};
async add() {
// add administrator role into the marketplace
this.marketplace.addFinanceManager(this.getAddress());
};
async remove(){
this.marketplace.addFinanceManager(this.getAddress());
};
getAddress() { return this.address }
}
// This can be decoupled using a Factory method
// that creates the role access // classes for us
class MarketplaceAccesControl implements AccessControlable {
accessController: AccessController;
marketplace: Contract; // web3/ethers contract instance
addAssetManager(_assetManagerAddr: string) {
this.accessController = new AssetManagerController(_assetManagerAddr, contract);
this.accessController.add();
}
removeAssetManager(_assetManagerAddr: string) {
this.accessController = new AssetManagerController(_assetManagerAddr, contract);
this.accessController.remove();
}
// more methods...
}
class Marketplace implements IMarketplace {
marketplace: Contract; //web3/ethers contract instance
accessController: AccessControlable;
configurer: Configurable;
acceptedCurrencies: string[];
assetValidators: Array<any>;
// more properties...
constructor (
marketplace: Contract, //web3/ethers contract instance
configurer: Configurable
) {
this.marketplace = marketplace;
this.configurer = configurer;
}
addAcceptedCurrency(_tokenERC20: string) {}
removeAcceptedCurrency(_tokenERC20: string) {}
withdraw(_to: string, amount: number) {}
addAssetValidatorDelegate(_account: string) {}
removeAssetValidatorDelegate(_account: string) {}
assignRnsDomain(_rnsDomainNode: any) {}
assignRnsNameGenerationStrategy(_strategy: string) {}
registerAsset(_asset: string) {}
validatorDelegateApprovesAsset(assetValidator: string, _asset: string){}
validatorDelegateRejectAsset(assetValidator: string, _asset: any) {}
assignOrderIdGeneratorStrategy(_strategy: string) {}
sellAsset(_asset: string) {}
}
```
## Proposal #3 (Merge Proposal 1 & 2)
```typescript=
/* Probably we need to segregate interfaces here */
interface IMarketplace {
changeRequireWhitelistedAsset(requireWhitelistedAsset: boolean) : Promise<boolean>;
changeRequireWhitelistedAssetProvider(requireWhitelistedAssetProvider: boolean) : Promise<boolean>;
changeRequireAssetValidation(requireAssetValidation: boolean) : Promise<boolean>;
changeRequireSaleStrategyPerAsset(requireSaleStrategyPerAsset: boolean) : Promise<boolean>;
changeRequireSameCurrencyPerAsset(requireSameCurrencyPerAsset: boolean) : Promise<boolean>;
changeRequireAssetSubdomain(requireAssetSubdomain: boolean) : Promise<boolean>;
changeSupportsStakingSlashing(supportStakingSlashing: boolean) : Promise<boolean>;
whitelistAsset(address: string) : Promise<boolean>;
removeAssetFromWhitelist(address: string) : Promise<boolean>;
isWhitelistedAsset(address: string) : Promise<boolean>;
addAcceptedCurrency(tokenERC20: string) : Promise<boolean>;
removeAcceptedCurrency(tokenERC20: string) : Promise<boolean>;
withdraw(to: string, amount: number) : Promise<boolean>;
addAssetValidatorDelegate(account: string) : Promise<boolean>;
removeAssetValidatorDelegate(account: string) : Promise<boolean>;
assignRnsDomain(rnsDomainNode: string) : Promise<boolean>;
assignRnsNameGenerationStrategy(strategy: string) : Promise<boolean>;
//registerAsset(Asset _asset) external;
validatorDelegateApprovesAsset(assetValidator: string, asset: string) : Promise<boolean>;
validatorDelegateRejectAsset(assetValidator: string, asset: string): Promise<boolean>;
assignOrderIdGeneratorStrategy(strategy: string) : Promise<boolean>;
sellAsset(asset: string) : Promise<boolean>;
}
interface AccessControlable {
addAdministrator(_adminAddr: string): Promise<void>;
removeAdministrator(_adminAddr: string):Promise<void>;
addAssetManager(_assetManagerAddr: string):Promise<void>;
removeAssetManager(_assetManagerAddr: string): Promise<void>;
addAssetValidatorManager(_assetValidatorManagerAddr: string): Promise<void>;
removeAssetValidatorManager(_assetValidatorAddr: string): Promise<void>;
addAssetValidator(_assetValidatorManagerAddr: string): Promise<void>;
removeAssetValidator(_assetValidatorAddr: string);
addFinance(_financeAddr: string): Promise<void>;
removeFinance(_financeAddr: string): Promise<void>;
addFinanceManager(_financeManagerAddr: string): Promise<void>;
removeFinanceManager(_financeManagerAddr: string): Promise<void>;
addAssetProviderManager(_assetProviderManagerAddr: string): Promise<void>;
removeAssetProviderManager(_assetProviderManagerAddr: string): Promise<void>;
addAssetProvider(_assetProviderAddr: string): Promise<void>;
removeAssetProvider(_assetProviderAddr: string): Promise<boolvoidean>;
}
class Marketplace implements IMarketplace, AccessControlable {
marketplace: IContract; //web3/ethers contract instance
acceptedCurrencies: string[];
assetValidators: Array;
rnsNameGenerationStrategy: any;
private assetWhitelist : AssetWhitelist;
// more properties...
constructor (
marketplace: IContract //web3/ethers contract instance
contractAddress: string,
) {
this.marketplace = marketplace;
}
// implements AccessControlable interface
addAssetManager(address: string) {
const assetManagerController = AccessControllerFactory.getAccessController(
AccessControllerType.ASSET_MANAGER,
contract,
);
assetManagerController.add(address);
}
removeAssetManager(address: string) {
const assetManagerController = AccessControllerFactory.getAccessController(
AccessControllerType.ASSET_MANAGER,
contract,
);
assetManagerController.remove(address);
}
addFinanceManager(address: string) {
const financeManagerController = AccessControllerFactory.getAccessController(
AccessControllerType.FINANCE_MANAGER,
contract,
);
financeManagerController.add(address);
}
removeFinanceManager(address: string) {
const financeManagerController = AccessControllerFactory.getAccessController(
AccessControllerType.FINANCE_MANAGER,
contract,
);
financeManagerController.remove(address);
}
// more methods...
addAcceptedCurrency(_tokenERC20: string): Promise<void> {}
removeAcceptedCurrency(_tokenERC20: string): Promise<void> {}
withdraw(_to: string, amount: number): Promise<void> {}
addAssetValidatorDelegate(_account: string): Promise<void> {}
removeAssetValidatorDelegate(_account: string): Promise<void> {}
assignRnsDomain(_rnsDomainNode: any): Promise<void> {}
assignRnsNameGenerationStrategy(_strategy: string): Promise<void> {}
registerAsset(_asset: string): Promise<void> {}
validatorDelegateApprovesAsset(assetValidator: string, _asset: string): Promise<void>{}
validatorDelegateRejectAsset(assetValidator: string, _asset: any): Promise<void> {}
assignOrderIdGeneratorStrategy(_strategy: string) {}
sellAsset(_asset: string): Promise<number> {}
// implements configuration interface
changeRequireWhitelistedAsset(requireWhitelistedAsset: boolean) : Promise<boolean>;
changeRequireWhitelistedAssetProvider(requireWhitelistedAssetProvider: boolean) : Promise<boolean>;
changeRequireAssetValidation(requireAssetValidation: boolean) : Promise<boolean>;
changeRequireSaleStrategyPerAsset(requireSaleStrategyPerAsset: boolean) : Promise<boolean>;
changeRequireSameCurrencyPerAsset(requireSameCurrencyPerAsset: boolean) : Promise<boolean>;
changeRequireAssetSubdomain(requireAssetSubdomain: boolean) : Promise<boolean>;
changeSupportsStakingSlashing(supportStakingSlashing: boolean) : Promise<boolean>;
}
interface IWhitelist {
add(address: string) : Promise<boolean>;
remove(address: string) : Promise<boolean>;
isWhitelisted(address: string) : Promise<boolean>;
}
class AssetWhitelist implements IWhitelist {
// TODO: implement
}
/* Suggestion
class CurrencyWhitelist implements IWhitelist { }
class AssetValidatorDelegateWhitelist implemts IWhitelist { }
*/
/**
* Abstract Role access
*/
interface AccessController {
add(address, marketplace): Promise<void>;
remove(address, marketplace): Promise<void>;
}
/*
* Concrete Roles Access in the marketplace
*/
class AssetManagerController implements AccessController {
private marketplace : Contract;
constructor(marketplace: Contract) {
this.marketplace = marketplace;
};
add(address) {
return this.marketplace.addAssetManager(address);
};
remove(address){
return this.marketplace.removeAssetManager(address);
};
}
class FinanceManagerController implements AccessController {
private marketplace : Contract;
constructor(marketplace: Contract) {
this.marketplace = marketplace;
this.address = address;
};
add(address) {
return this.marketplace.addFinanceManager(address);
};
remove(address){
return this.marketplace.removeFinanceManager(address);
};
}
enum AccessControllerType {
ASSET_MANAGER;
FINANCE_MANAGER;
ASSET_VALIDATOR_MANAGER
ASSET_PROVIDER_MANAGER;
ADMINISTRATOR;
OWNER;
}
class AccessControllerFactory {
public static getAccessController(
type: AccessControllerType,
marketplace: IContract,
): AccesController {
switch(type){
case AccessControllerType.ASSET_MANAGER:
return new AssetManagerController(marketplace);
case AccessControllerType.FINANCE_MANAGER:
return new FinanceManagerController(marketplace);
// more types...
default:
return null;
}
}
}
// Contract interactor suggestion
class IContract {
addAcceptedCurrency(address: string) : Promise<boolean>;
}
// Discuss: Basically a middleman
// - https://refactoring.guru/smells/middle-man
// Ideally, we would like to use the same interface used by Ethers (probs doesn't exist)
// Or use TypeChain ?
class
implements IContract {
private ethers : any;
constructor(ethers: any) {
this.ethers = ethers;
}
addAcceptedCurrency(address: string) : Promise<boolean> {
this.ethers.addAcceptedCurrency(address);
}
}
```