For marketplaces : Organizing sales
The architecture of Marmalade-NG allow creating a pure de-centralized marketplace, without the need for a centralized back-end. All needed data is stored on-chain.
Pre-checks
Before putting on sales a token, the marketplace should examine closely the list of policies of the token:
If the token implements
DISABLE-SALE=> Impossible to sell.Whether the token implements
MARKETPLACE, allowing the marketplace to charge fees.Sales mechanisms implemented
FIXED-SALEand/orAUCTION-SALEand/orDUTCH-AUCTION-SALE.
Depending on the sales mechanisms implemented by the token and by the marketplace itself, the user should be able to choose how to sell his token.
Unknown policies handling
A token may have some custom policies. A custom policy could interfere in many ways during the sale process. (including causing a loss of funds for users). If policies-to-list or from-policies is used, the unknown policies are referred as a unique identifier.
- Depending on its own policy, the Marketplace can:
Ignore unknown policies
Whitelist reviewed policies (recommended)
Refuse any sales with unknown policies
Guard policy handling
A token may implement the guard policy. The guard policy is less powerful than a custom policy, but gives the possibility to create custom and complex solutions. As a consequence, whether the guard policy will authorize a sale is unpredictable. The dApp should try it using a local call.
However, as soon as the sale offer has been made, the guard policy can’t interfere anymore.
Thus, a guard policy should be safe for marketplace users.
Marketplace fee object
When the marketplace policy is used for charging a fee, the marketplace must provide a fee object marmalade_marketplace that defines the fee parameters:
minimal/maximum/rate of the fee
currency of the fee
shared fee rate
payable account.
Such an object is identified by a hash. The Marketplace may manage one or a set of genuine fee objects (and their corresponding hashes)
This will give the possibility to the marketplace to only list genuine sales.
Note: The field marketplace-name should remain as informative only. Nobody should rely on this field, since it can
be crafted by anyone. Only the full object represented by its hash is reliable.
Fixed quote sales
Starting the sale
A sale has to be started by invoking the ledger defpact function (sale).
The timeout parameter can be set to a finite timeout or infinite with the constant NO-TIMEOUT.
Listing
The list of current active sales can be retrieved on-chain by using get-all-active-sales.
But if the marketplace applies a strict policy of only displaying the sales that have been created through it. (or at least the sales that have accepted to comply with the marketplace fees), the function get-active-sales-by-market-hash can be used to retrieve the list of sales. This function has to be called with the list of known Genuine hashes
The marketplace policy is not aware of the type of sale it is. When is sale is retrieved through the marketplace policy module, it should be validated by the fixed-sale module get-sale.
Moreover, it is recommended to inspect the policies list of the retrieved sale to ensure they are compliant with Unknown policies handling
Ending the sale
When a buyer wants to buy the token, the dApp has to call get-sale to check the conditions:
price
currency
escrow account
end date
- The continuation transaction must be sent with the following parameters:
Step = 1
Rollback = False
Data:
{"buyer": buyer,
"buyer-guard": buyer-guard
}
The transaction may include a shared_fee object.
And the following installed capacity:
(currency.TRANSFER buyer escrow-account price)
Auction sale
Starting the sale
A sale has to be started by invoking the ledger defpact function (sale).
The timeout parameter must be a finite timeout.
Listing
The listing procedures are similar to Listing, but the policy-auction-sale policy module has to be used
instead of the fixed-auction-sale:
Bidding
When a buyer wants to bid for a token, the dApp has to call get-sale to check the conditions:
current-price / start-price / increment
currency
escrow account
end date
The minimum price should be calculated by the dApp with the following algorithm:
IF current-price = 0
THEN
minimum-price = starting-price
ELSE
minimum-price = current-price * increment
ENDIF
Note: The user is able to bid more than the minimum price.
The bid must be done using the function place-bid of the policy-auction-sale module.
The transaction may include a shared_fee object.
And the following installed capacity:
(currency.TRANSFER buyer escrow-account new-price)
Ending the sale
- The continuation transaction can be triggered by:
the seller
the buyer
or anybody else, including a bot that works for the marketplace.
- It is necessary to retrieve the following parameters using get-sale:
buyer
end-date
Ending the sale is only possible if end-date is earlier than the current date-time.
Depending on the value of the buyer field, one of the two procedures must be done:
Withdrawal (buyer = “”)
It means that nobody has proposed a bid.
- A defpact continuation transaction must be sent with:
Step = 0
Rollback = True
Nothing more is needed. The tokens will be sent back to the seller.
Settle transaction (buyer not = “”)
The buyer must be retrieved with get-sale.
The buyer guard must be retrieved with account-guard. The dApp shouldn’t try to infer the guard for the account name (e.g: Extracting the key from a k:account name).
- A defpact continuation transaction must be sent with:
Step = 1
Rollback = False
Data:
{"buyer": buyer,
"buyer-guard": buyer-guard
}
The transaction must include a shared_fee object, if the bid has been done with such object. This information can be retrieved during listing.