Skip to content

Latest commit

 

History

History
605 lines (526 loc) · 28.3 KB

fip-0026.md

File metadata and controls

605 lines (526 loc) · 28.3 KB
fip title status type author created updated
26
FIO Domain Marketplace
Final
Functionality
Isaiah Williams - EOS BlockSmith, Thomas Le - EOS BlockSmith
2021-02-05
2022-04-25

Abstract

What we are planning to create is a marketplace where users can buy and sell FIO Domains. Users will interact with the frontend website to view and place domains up for sale. The frontend will interact with the FIO Escrow Smart Contract to facilitate transactions between users who buy and sell domains.

Proposed new actions and end points

Contract Action Endpoint Description
fio.escrow listdomain list_domain User puts domain up for sale
fio.escrow cxlistdomain cancel_list_domain Seller of domain decides not to sell and cancels their listing
fio.escrow buydomain buy_domain User buys a domain that is up for sale
fio.escrow setmrkplcfg set_marketplace_config The mrkplconfig table holds configs for a given marketplace. This action writes to that table.
fio.escrow cxburned none This is an admin action that is only called from fio.address::burnexpired to cancel the listing of a domain if it is burned and still listed for sale (not already sold or cancelled)
fio.address xferescrow none Transfers domain to fio.escrow. Called from fio.escrow only
Endpoint Description
get_escrow_listings Returns all listings based on status with optional actor parameter for further filtering

Modified actions

Contract Action Endpoint Description
fio.token transfer none Added code to fio.token::transfer so that, from the fio.escrow contract, it can transfer tokens from two accounts.
fio.address burnexpired burn_expired If a domain is expired and still listed, when it is going to be burned it needs to also be removed as a listing for sale.
fio.treasury bprewdupdate ? added EscrowContract to authorization list
fio.treasury bppoolupdate ? added EscrowContract to authorization list
fio.treasury fdtnrwdupdat ? added EscrowContract to authorization list

Terminology

  • Listing - a domain that is up for sale
  • FIO Domain Marketplace - the frontend website
  • Seller - the seller of a domain
  • Buyer - the buyer of a domain
  • Listing Fee - fee paid to the marketplace from the seller to the marketplace. Flat fee in FIO.
  • Commission Fee - fee paid to the marketplace when a domain is sold. This is a percentage of the sale price.
  • Escrow Account (fio.escrow) - the account that owns the smart contract.
  • E-Break - Term used within the contract for a setting that will disable all actions in the event of a major exploit or bug found to mitigate damages.

Motivation

There does not currently exist a platform for buying, selling, and trading FIO Domains. As the popularity of FIO grows, the likelihood of a desired domain being available decreases. It is also common for individuals to purchase names of popular name brands in order to later sell the domain to the company who owns the brand (name squatting). Without a marketplace for domains to be sold, these transactions become difficult. By providing ease of use solutions to name and address transactions, a marketplace also increases the revenue flow of block producers by increasing the amount of fees generated by each transaction.

Specification

Core Concept

Users will interact with the frontend website to view and place domains up for sale. The frontend will interact with the FIO Escrow Smart Contract to facilitate transactions between users who buy and sell domains. The diagram below displays how the user, the website, the smart contract and the account that owns the smart contract all work together.

Image of UML Diagram

This diagram reads left to right and top to bottom. There are three different scenarios outlined and they are distinguished by the color of the arrows. The first scenario, in red, starts will the user using the website to place a domain up for sale for a specified price. This user is denoted as "seller." To initiate this scenario, the seller will pay a listing fee to list their domain for sale on the marketplace. The website then communicates that the smart contract needs to use the "listdomain" action, which will transfer ownership of the domain to an “escrow_account” and place that domain for sale on the website. The escrow account is the account that owns the escrow smart contract and, acts as an intermediary that will hold the domain while listed.

The second scenario, in blue, starts will the seller canceling their listing on the website. The website then communicates with the smart contract in order to transfer ownership of the domain from the escrow account back to the seller.

The last scenario, in green, starts with a different user buying a listing on the website. This second user is denoted as "buyer." The website then communicates with the smart contract in order to transfer ownership of the address to the buyer and transfer the funds used to buy the domain to the seller. The marketplace will take a commission for facilitating this transaction.

New Tables

Listing table

domainsale

Holds all the domains currently available for sale with related information like the owner and amount of FIO the user wants.

We are saving the commission fee per domain listing because the commission fee can be changed but for existing listings it should not change because they agreed to list with a certain commission fee.

Column Type Description
id uint64 Primary key
owner uint64 actor of owners account
ownerhash uint128 hashed value of owner
domain string name of domain for sale
domainhash uint128 hashed value of domain
sale_price int64 sale price in SUF
commission_fee int64 commission fee applied to sale price
date_listed uint64 date at time of listing
status uint8 status = 1: on sale, status = 2: Sold, status = 3; Cancelled
date_updated uint64 date last updated status, this will be when the listing was sold or cancelled
Indexes
  • Primary Key
  • bydomain
  • byowner

Marketplace Config Table

mrkplconfig

Holds information related to the marketplace.

Column Type Description
id uint64 Primary key
owner uint64 actor of owners account
ownerhash uint128 hashed value of owner
commission_fee uint64 Commission fee is a percentage taken out of the sale price when a domain is sold
listing_fee uint64 Listing fee is taken up front for creating a listing
e_break uint64 This is a setting that will disable all actions in the event of a major exploit or bug found to mitigate damages

Indexes

  • primary key
  • bymarketplace
  • byowner

New actions and end points

Get Escrow Listings

Returns all listings based on status with optional actor parameter for further filtering

/get_escrow_listings

Request

Parameter Required Format Definition
Status Yes Integer Value 1-3 status = 1: on sale, status = 2: Sold, status = 3; Cancelled
actor No String of actor name
limit No Positive Int Number of records to return. If omitted, all records will be returned. Due to table read timeout, a value of less than 1,000 is recommended.
offset No Positive Int First record from list to return. If omitted, 0 is assumed.
Example
{
    "status": 1,
    "offset": 0,
    "limit": 1000,
    "actor": "wjeo4abnk4c2"
}

Processing

  • Request is validated per Exception handling
  • All Escrow listings with the status of the provided parameter
  • If actor is provided it takes the results and only returns records of that status and with that actor name

Exception handling

Error condition Trigger Type fields:name fields:value Error message
Invalid Status value Value of status is not 1, 2 or 3 400 "status" Value sent in, i.e. "5" "Invalid status value"
Invalid limit limit is not valid 400 "limit" Value sent in, e.g. "-1" "Invalid limit"
invalid offset offset not valid 400 "offset" Value sent in, e.g. "-1" "Invalid offset"
No Escrow Listings There are no escrow listings based on the parameters. 404 "No Escrow Listings"

Response

Group Parameter Format Definition
listings JSON Array Array of Escrow Listings
listings id Int ID of Escrow Listings
listings commission_fee String commission percentage
listings date_listed string timestamp when the listing was created
listings date_updated string timestamp when the listing was last updated
listings domain String the FIO domain being listed
listings owner String account name of the owner of the domain
listings sale_price Int price the owner wants for the domain, in SUFs
listings status Int Status of the listing.
more Int Number of results remaining
Example
{
  "listings": [
    {
        "id": 0,
        "commission_fee": "6.00000000000000000",
        "date_listed": "2021-11-30T20:54:08",
        "date_updated": "2021-11-30T20:54:08",
        "domain": "agreement",
        "owner": "wjeo4abnk4c2",
        "sale_price": 300000000000,
        "status": 1
    }
  ],
  "more": 0
}

List Domain for Sale

This action will post the domain up for sale on the marketplace for a specified price. A listing fee is collected from the domain owner for this action that goes to the marketplace. The domain is transferred to the fio.escrow account for the duration of the listing. This will prevent the ability to change the domain_public setting but it WILL allow new addresses to be registered on that domain if it is already set to public.

Contract: fio.escrow

New fee: list_domain, not bundle eligible

New Endpoint: list_domain

Ram Increase: To be determined during implementation

New action: listdomain

Request body

Parameter Required Format Definition
actor Yes 12 character string Valid actor of signer (seller)
fio_domain Yes FIO Domain Valid and FIO Domain that does not expire within the next 90 days
sale_price Yes Positive Int The amount of SUFs for which the seller wants to sell their domain
max_fee Yes Positive Int Maximum amount of SUFs the user is willing to pay for fee. Should be preceded by /get_fee for correct value.
tpid Yes FIO Address FIO Address of the entity which generates this transaction. TPID rewards will be paid to this address. Set to empty if not known.
Example
{
    "actor": "2odzomo2v4pe"
    "fio_domain": "alice",
    "sale_price": 20000000000,
    "max_fee": 1000000000,
    "tpid": "rewards@wallet"
}

Processing

  • Request is validated per exception handling
  • Hash both the actor, fio_domain to store alongside the string, for indexing.
  • Retrieve current commission_fee from the marketplace config table to be saved with the listing
  • Add domain to the domainsale table with relevant information
  • Transfer domain from seller to fio.escrow account.
  • Change status flag on domainsale table to 1. (status = 1: on sale, status = 2: Sold, status = 3; Cancelled)
  • Update date_updated column in domainsale table.
  • A listing fee is collected by the marketplace and is set in the marketplace config table
  • Verify tx does not exceed max transaction size.
  • Increase account RAM

Exception handling

Error condition Trigger Type fields:name fields:value Error message
Invalid sale price Supplied sale_price (in SUF) is not greater than 1 FIO 400 "sale_price" Value sent in, e.g. "1000000000" "Sale price must be greater than 1 FIO"
Invalid sale price Supplied sale_price (in SUF) is greater than 999,999 FIO 400 "sale_price" Value sent in, e.g. "1000000000000000" "Sale price must be less than 999999 FIO"
Invalid fee value max_fee format is not valid 400 "max_fee" Value sent in, e.g. "-100" "Invalid fee value"
Fee exceeds maximum Actual fee is greater than supplied max_fee 400 "max_fee" Value sent in, e.g. "1000000000" "Fee exceeds supplied maximum"
Invalid FIO Domain format FIO Domain format is not valid 400 "fio_domain" Value sent in, e.g. "alice+123" "Invalid FIO domain"
FIO Domain expired FIO Domain is expired 400 "fio_domain" Value sent in, e.g. "alice" "FIO Domain expired. Renew first."
Not owner of FIO Domain The signer does not own the domain 403 Type: invalid_signature
Actor not signer The signer and the actor do not match 403 Type: invalid_signature

Response Body

Parameter Format Definition
status String OK if successful
listing_id Int id of the listing
fee_collected Int Amount of SUFs collected as fee
Example
{
  "status": "OK",
  "listing_id": 1
  "fee_collected": 2000000000
}

Cancel Domain Listing

This action will take the domain off of the marketplace and return ownership of the domain to the seller.

New action: cxlistdomain

Contract: fio.escrow

New fee: cancel_list_domain, not bundle eligible

New Endpoint: cancel_list_domain

Ram Increase: To be determined during implementation

Request

Parameter Required Format Definition
fio_domain Yes FIO Domain Valid and unexpired FIO Domain
actor Yes 12 character string Valid actor of signer (seller)
max_fee Yes Positive Int Maximum amount of SUFs the user is willing to pay for fee. Should be preceded by /get_fee for correct value.
tpid Yes FIO Address FIO Address of the entity which generates this transaction. TPID rewards will be paid to this address. Set to empty if not known.
Example
{
    "actor": "2odzomo2v4pe",
    "fio_domain": "alice",
    "max_fee": 1000000000,
    "tpid": "rewards@wallet"
}

Processing

  • Request is validated per exception handling
  • Change status flag on domainsale table to 3. (status = 1: on sale, status = 2: Sold, status = 3; Cancelled)
  • Update date_updated column in domainsale table.
  • Transfer domain from fio.escrow to actor which will be verified to be the name of the account that originally listed the domain
  • Verify that the fee for this does not exceed the max fee specified.
  • Charge appropriate fee
  • Verify tx does not exceed max transaction size.
  • Increase account RAM

Exception handling

Error condition Trigger Type fields:name fields:value Error message
Invalid FIO Domain format FIO Domain format is not valid 400 "fio_domain" Value sent in, e.g. "alice" "Invalid FIO domain"
FIO Domain expired FIO Domain is expired 400 "fio_domain" Value sent in, e.g. "alice" "FIO Domain expired. Renew first."
FIO Domain listing not found Supplied fio_domain is not listed on domainsale table. 400 "fio_domain" Value sent in, e.g. "alice" "FIO domain not listed in domainsale table"
Invalid fee value max_fee format is not valid 400 "max_fee" Value sent in, e.g. "-100" "Invalid fee value"
Fee exceeds maximum Actual fee is greater than supplied max_fee 400 "max_fee" Value sent in, e.g. "1000000000" "Fee exceeds supplied maximum"
Insufficient funds to cover fee Account does not have enough funds to cover fee 400 "max_fee" Value sent in, e.g. "1000000000" "Insufficient funds to cover fee"
Not owner of FIO Domain The signer does not own the domain 403
Actor not signer The signer and the actor do not match 403 Type: invalid_signature

Response body

Parameter Format Definition
status String OK if successful
fee_collected Int Amount of SUFs collected as fee
Example
{
  "status": "OK",
  "fee_collected": 2000000000
}

Buy Domain Listing

This action facilitates the purchase of a domain listed for sale. The buyer will pay the full listed price + tx fee. A commission calculated by multiplying the commission_fee by the sale price is subtracted and sent to the marketplace owner account. The remaining FIO will be sent to the seller and the domain will be transferred to the buyer.

Example:

  • Commission fee is set to 5%
  • Domain listed for 500 FIO
  • Buyer pays 500 FIO + tx fee
  • Commission calculated by 0.05 * 500 = 25
  • 25 FIO is sent to marketplace owner account in marketplace config table
  • 475 FIO is sent to seller
  • Domain is transferred from fio.escrow to buyer.

New action: buydomain

Contract: fio.escrow

New fee: buy_domain, not bundle eligible

New Endpoint: buy_domain

Ram Increase: To be determined during implementation

Request

Parameter Required Format Definition
actor Yes 12 character string Valid actor of signer (buyer)
fio_domain Yes FIO Domain Domain that can be found on the domainsale table.
max_buy_price Yes Positive Int Amount of FIO, in SUFs, that the buyer expects to pay
max_fee Yes Positive Int Maximum amount of SUFs the user is willing to pay for fee. Should be preceded by /get_fee for correct value.
tpid Yes FIO Address FIO Address of the entity which generates this transaction. TPID rewards will be paid to this address. Set to empty if not known.
Example
{
    "actor": "2odzomo2v4pe",
    "fio_domain": "alice",
    "max_buy_price": 100000000000,
    "max_fee": 1000000000,
    "tpid": "rewards@wallet"
}

Processing

  • Request is validated per exception handling
  • Calculate commission amount by multiplying commission_fee by the sale_price
  • Send, from buyer, commission amount sent to marketplace owner.
  • Send, from buyer, rest ( sale price minus commission amount ) of sale price to the domain seller
  • Transfer domain from fio.escrow to buyer.
  • Change status flag on domainsale table to 2. (status = 1: on sale, status = 2: Sold, status = 3; Cancelled)
  • Update date_updated column in domainsale table.
  • Verify that the fee for this does not exceed the max fee specified.
  • Charge appropriate fee
  • Verify tx does not exceed max transaction size.
  • Increase account RAM

Exception handling

Error condition Trigger Type fields:name fields:value Error message
FIO Domain listing not found Supplied fio_domain is not listed on domainsale table. 400 "fio_domain" Value sent in, e.g. "alice" "FIO domain not listed in domainsale table"
FIO Domain expired FIO Domain is expired 400 "fio_domain" Value sent in, e.g. "alice" "FIO Domain expired. Renew first."
Insufficient Funds buyer doesn't have enough funds to cover domain cost and fee 400 "buy_price" Value sent in, e.g. "1000000000" "Not enough FIO"
Invalid fee value max_fee format is not valid 400 "max_fee" Value sent in, e.g. "-100" "Invalid fee value"
Fee exceeds maximum Actual fee is greater than supplied max_fee 400 "max_fee" Value sent in, e.g. "1000000000" "Fee exceeds supplied maximum"
Sale Price exceeds buy_price parameter Actual sale price of domain exceeds the buy_price supplied 400 "buyer_max_buy_price" Value sent in, e.g. "100000000" "sale price exceeds supplied buy price"
Actor not signer The signer and the actor do not match 403 Type: invalid_signature

Response body

Parameter Format Definition
status String OK if successful
buy_price Int Amount of SUFs collected for buy_price
fee_collected Int Amount of SUFs collected as fee
Example
{
  "status": "OK",  
  "max_buy_price": 100000000000,
  "fee_collected": 2000000000
}

Set Marketplace Config

Contract: fio.escrow

New Endpoint: set_marketplace_config

Ram Increase: To be determined during implementation

New action: setmrkplcfg

This sets the marketplace configurations.

When calling this action for the very first time, to set the owner of the marketplace with the actor parameter, it will need to be an msig by eosio.prods.

Once the marketplace actors name is in the table, this same action can be called by the marketplace to set the parameters.

When this action is called as an msig by eosio.prods it will not be charged a fee, but if the marketplace owner calls it, there will be a fee.

Request

Parameter Required Format Definition
actor Yes 12 character string Valid actor of the owner of the marketplace.
listing_fee No FIO amount in SUFs Flat fee in FIO taken up front for listing a domain for sale
commission_fee No Decimal number less than 25 Used to calculate commission fee from sale price. This is a percentage.
e_break No 0 for off, 1 for on Enables or disables e-break
max_fee Yes Positive Int Maximum amount of SUFs the user is willing to pay for fee. Should be preceded by /get_fee for correct value.
Example
{
    "owner": "awesomemrkpl",
    "listing_fee": "3000000000",
    "commission_fee": 6,
    "e_break": 0,
    "max_fee": 2000000000
}

Processing

  • Request is validated per exception handling
  • Find marketplace
  • Determine if this action is being called as an msig by eosio.prods
    • If by an msig by eosio.prods it will allow the creation of a record on the table
      • Set owner
      • Set commission fee
      • Set listing fee
      • Set e-break
    • If not an msig by eosio.prods it will only allow updating 3 parameters
      • Modify commission fee
      • Modify listing fee
      • Modify e-break
  • Charge appropriate fee if caller not eosio
  • Verify tx does not exceed max transaction size
  • Increase account RAM

Exception handling

Error condition Trigger Type fields:name fields:value Error message
listing_fee No FIO amount in SUFs Flat fee in FIO taken up front for listing a domain for sale
commission_fee No Decimal number less than 25 Used to calculate commission fee from sale price. This is a percentage.
e_break No 0 for off, any positive number for on Enables or disables e-break
max_fee Yes Positive Int Maximum amount of SUFs the user is willing to pay for fee. Should be preceded by /get_fee for correct value.
Actor not signer The signer of this request must be eosio 403 Type: invalid_signature
Actor not marketplace owner The signer of this request must match marketplace owner (once a record is present) 403 Type: invalid_signature

Response body

Parameter Format Definition
status String OK if successful
Example
{
  "status": "OK"
}

Cancel Burned

Contract: fio.escrow

New Endpoint: none

Ram Increase: To be determined during implementation

New action: cxburned

This action is called when a listing is found for a domain that is being burned. It will only be called if the listing is still active and it sets the status to 3, cancelled.

Request

Parameter Required Format Definition
domainhash Yes uint128 Hashed value of domainname being cancelled
Example
{
    "domainhash": "0xca0c8869bd11e8add2becc729ce08368",
}

Processing

  • Request requires to be from AddressContract.
  • Use domainhash to find entry in domainsales table.
  • Check status is equal to 1 (still an active listing) and if so
  • Set status to 3, cancelled
  • Update date_updated column in table

Exception handling

N/A. Handled by has_auth() only

Response

none, inline action

Example

none

Transfer for Escrow

Contract: fio.address

New Endpoint: n/a

Ram Increase: n/a

New action: xferescrow

This is an action added to the fio.address contract specifically for the fio.escrow contract. Only the EscrowContract can call this action.

This action facilitates transferring the domain for sale to fio.escrow and back to the seller in the case of a cancel. In the case of a sale it transfers to the buyer.

Request

Parameter Required Format Definition
fio_domain Yes FIO domain name valid, registered, unexpired domain
public_key Yes FIO public key Valid FIO Domain that is already listed
isEscrow Yes bool This is a flag that is used to determine if the domain is transferred to fio.escrow or a normal account
actor Yes FIO Domain Valid FIO Domain that is already listed
Example

Processing

  • Request is validated per exception handling
  • Find domain
  • if isEscrow is true
    • Set domain's owner to fio.escrow
  • if isEscrow is not true
    • Validate public key
    • get account actor name from public key
    • set domains owner to name obtained from public key

Exception handling

Error condition Trigger Type fields:name fields:value Error message
Insufficient Funds buyer doesn't have enough funds 400 "Not enough FIO"
Invalid FIO Domain format FIO Domain format is not valid 400 "fio_domain" Value sent in, e.g. "alice" "Invalid FIO domain"
FIO Domain expired FIO Domain is expired 400 "fio_domain" Value sent in, e.g. "alice" "FIO Domain expired. Renew first."
FIO Domain not registered FIO Domain is not registered 400 "fio_domain" Value sent in, e.g. "alice" "FIO Domain not registered"

Response

none, inline action

Example

none

Modified Actions

Contract: fio.token

Modified Action: transfer

  • Added the following code to fio.token::transfer so that, from the fio.escrow contract, it can transfer tokens from two accounts.
if (from != SYSTEMACCOUNT && from != TREASURYACCOUNT && from != EscrowContract) {
    if(!has_auth(EscrowContract)){
        check(to == TREASURYACCOUNT, "transfer not allowed");
    }
}
eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(TREASURYACCOUNT) || has_auth(EscrowContract)),
             "missing required authority of treasury or eosio");

Note: I added a && from != EscrowContract and then wrapped the check() to see if the caller !has_auth(EscrowContract).

Contract: fio.address

Modified Action: burnexpired

This action needs to be updated because there is no expiration to a domain being listed. If a domain is expired and still listed, when it is going to be burned it needs to also be removed as a listing for sale.

Added Processing
  • Look up domain that is being burned in the domainsales table
  • If found, remove the entry from domainsales
    if (nameiter == nameexpidx.end()) {
      domains.erase(domainiter);
      recordProcessed++;
      
      // ADDED
      // Find any domains listed for sale on the fio.escrow contract table
      auto domainsalesbydomain = domainsales.get_index<"bydomain"_n>();
      auto domainsaleiter = domainsalesbydomain.find(domainhash);
      // if found, call cxburned on fio.escrow
      if(domainsaleiter != domainsalesbydomain.end()){
        if(domainsaleiter->status == 1) {
          action(permission_level{get_self(), "active"_n},
          EscrowContract, "cxburned"_n,
          make_tuple(domainhash)
        ).send();
      }
      // END ADDED  
    }
}

Release information

Released in:

Rationale

Domain Transfers

An approach was considered to keep the domain ownership with the seller until the buyer makes a purchase and transfer then. However, we feel that having the ownership of the domain transferred to fio.escrow account is necessary because it makes sure that when a buyer comes along that it is 100% available for sale. If the ownership doesn't transfer then the seller can still use the domain until it sells, and then, if a buyer comes along it might suddenly, without notice, disappear from their account.

  • Domains set to public are still able to have addresses registered on them
  • We may not need api end-points for our actions so none are included in this document, as of right now
  • Domains cannot be changed from public to private or private to public while listed for sale.
  • Any section that is blank will be filled out in the future as we get further along in the process

Backwards Compatibility

TBD

Future considerations

  • Functionality for addresses
  • Being able to renew a domain upon purchase
  • Messaging system
  • Expiring domain page to see all domains that are about to expire
  • For the frontend to facilitate the registering of usernames to domains
  • Being able to send an offer to the seller and they can either accept or decline
  • “Willing to sell” designation
  • Being able to send and receive FIO

Discussion links