stacksgov / sips

Community-submitted Stacks Improvement Proposals (SIPs)
131 stars 80 forks source link

Trait for Marketplace functions #51

Open friedger opened 2 years ago

friedger commented 2 years ago

There should be a SIP that defines smart contract functions that enables an open, decentralized market place for digital assets. These assets must implement the operable trait (#52).

Owners of operable assets should be able to list and unlist their token. Buyers should be able to buy the assets from the owner.

The marketplace trait can be implemented as part of the asset contract (usually not recommended) or as an independent contract.

A simple trait would look like this:

(use-trait commission-trait .commisions.trait)
(define-trait marketplace
    (
        ;; announce listing to global marketplace
        ;; must return `(ok true)` on success, never `(ok false)`
        ;; must send a list event
        ;; @param id; identifier of NFT or amount of FTs
        ;; @param price: of sale in micro STX
        ;; @param commission: action to happen after sale
        (list-in-ustx (uint uint <commission-trait>) (response bool uint))

        ;; announce delisting to global marketplace
        ;; must return `(ok true)` on success, never `(ok false)`
        ;; must send a delist event
        ;; @param id; identifier of NFT or amount of FTs
        (unlist-in-ustx (uint) (response bool uint))

        ;; buy and announce delisting to global marketplace
        ;; must return `(ok true)` on success, never `(ok false)`
        ;; commission must match the one set during listing
        ;; must send a delist event
        ;; @param id; identifier of NFT or amount of FTs
        ;; @param commission: action to happen after sale        
        (buy-in-ustx (uint  <commission-trait>) (response bool uint))

        ;; read-only function defining the asset
        (get-asset () (response {fq-contract: string, asset-class: string} uint))
    )
)

(define-trait commission
    (
        ;; additional action after a sale happened, usually a fee transfer for marketplaces
        ;; must return `(ok true)` on success, never `(ok false)`
        ;; @param id; identifier of NFT
        ;; @param price: of sale in micro STX
        (pay (uint uint) (response bool uint))
    )
)

Security

As commission-traits can call any functions in the name of the tx-sender, it is important that a web app only offers commission contracts that are well understood. In particular, appropriate post-conditions have to be created.

If asset contracts want to control trades they have to restrict which operators are approved. Note, that royalties to an artist of an NFT can be part of the commission if agreed with the marketplace. They can also be implemented in the NFT directly.

Related Work

Loopbom https://github.com/radicleart/clarity-market

Megapont Ape Club https://explorer.stacks.co/txid/SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.megapont-ape-club-nft?chain=mainnet

//cc @radicleart @MarvinJanssen @Jamil @dcsan @dantrevino

radicleart commented 2 years ago

Reference material: https://github.com/ethereum/EIPs/issues/2907

Jamil commented 2 years ago

Some thoughts here based on pain points dealing with the Megapont contract:

additional thoughts:

obsidianbtc commented 2 years ago

Agreed here that exposing the total % in the commission trait and including commission in this listing price, not on top would be great.

LNow commented 2 years ago

@friedger whole concept can be generalized and allow listing/un-listing/buying NFT's using STX and any SIP-010 compliant FT using one interface (see #60).

314159265359879 commented 2 years ago

I would love to see the trait for a marketplace function standardized in a SIP. Do I understand correctly we are closing this in favor of #60: a more generalized interface so that any SIP-010 token can be used alongside STX to purchase said listed NFT?

I think current implementations on mainnet still have the commissions added on top of the listed price. Whereas @Jamil and @obsidianbtc were in favor of changing to listing with a price including the commissions, is that still the case? Would this need to be implemented in #60? Or would you prefer to keep the current way of working in the standard as you seem to have worked out a UI/UX to accommodate it already?

friedger commented 2 years ago

@314159265359879 This more generalized interface would be (list-in-token (<transferable-trait> uint uint <commission-trait>) (response bool uint)) ...

The problem with the commission is that I don't see a standard way of calculating it. The commission contract can be an auction contract and the user initially listed it with a minimum price. Using the same price in list and buy function looks too rigid to me.

The commission contract can be also the single registry contract for all supported nfts because the contract-caller is the nft contract.