-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trait for Tradables/Marketplace functions #40
Comments
#35 is about transfer with memo. This one is about listing and purchase. Both try to define the trait for both FTs and NFTs. |
We might want to add more option to set the price like |
This seems rather limiting. Can you explain how these traits would work in practice? What if I don't want to sell for STX but another NFT? Or a SIP010? Or something else entirely? Will the future token developer need to implement a plethora of these? It makes more sense to build upon the |
@MarvinJanssen Indeed, this is only a small part of the opportunities you have to exchange your assets. You can always go to a market and swap your asset for another one. I could imagine services that enable on the spot exchange of the buyers assets to the requested ones from the seller. This SIP is only an extension to SIP-9 and SIP-10. I don't see how A possible implementation is here: https://explorer.stacks.co/txid/0x0c983e4a0138f86d4dc91e3eeb277f14fafb1a118fef1035ff06db84093697d1?chain=testnet This SIP would explore the ability of owner to participate in an open, global market without 3rd parties involved. Instead of covering all possible this covers the main uses case for selling an asset in STX or BTC. Sale with FTs can't use the same trait because the FT trait needs to be passed in as a parameter. Something like this would be possible (list-asset (uint uint <tradable-trait> <commission-trait>) (response bool uint))
(buy-asset (uint <tradable-trait> <commission-trait>) (response bool uint)) Then there would be two special tradables for STX and SATS. |
Do I understand it correctly that main idea behind this SIP is to eliminate middle man and embed micro marketplace in token itself, and allow token owners to put them on sale without transferring them to 3rd party (potentially faulty or malicious) contracts? |
@LNow Correct, for a user owned internet. The role of marketplaces is to aggregate, filter, present,.. |
Here is a first implementation: https://explorer.stacks.co/txid/SP3D6PV2ACBPEKYJTCMH7HEN02KP87QSP8KTEH335.megapont-ape-club-nft?chain=mainnet |
@friedger I like it. One remark - if we want to make sure commissions and royalties are payed correctly, NTF should have list of allowed Based on above I would add one more function to (get-allowed-commisions () (response (list 10 <commission-trait>) uint) |
I do not like it, at least not in this form. Diverging needs will create a situation of ever-growing and more complex token contracts. Think of sale expiry, tiered commissions, royalties, will token contract developers have to deal with all of that? I do not see a lot of upside over having an exchange contract that can call into |
Is this basically to enable non-custodial NFT sales @friedger ? a way to enable delegated sales without asset transfer? I'm still a bit new around here but this seems like a critical proposal. @MarvinJanssen are you proposing to add a bunch of parameters to the I would 👍 +1 keeping it simple to solve for the 95% of NFT transactions that happen out there and not try to perfect for all the possible future use cases for NFTs. some other references: setApprovable@radicleart (numberOne marketplace) is working on a proxieshttps://docs.opensea.io/docs/1-structuring-your-smart-contract#creature-erc721-contract |
@dcsan have made some more progress on this and deployed a version on staging here ST1NXBK3K5YYMD6FD41MVNP3JS1GABZ8TRVX023PT.nft-tradable-trait @friedger this is similar to yours but i've included ability to approve another (ie marketplace) address in order to delegate the transfer or listing function to the marketplace. @MarvinJanssen I've deliberately left royalties/commissions etc out of this - do you see these as additional optional traits or off chain features - to keep the contract simple? Can you elaborate on what you think this tradable standard should look like? |
BTW the work in progress is in https://github.com/radicleart/clarity-market branch |
A bit of history: When defining SIP9, I left out the Both I understand that defining implicit conditions to move the asset does not sound right like @MarvinJanssen pointed out. What is a better solution? Defining the condition externally in a contract? Does it give the user enough control over their assets? Should we introduce a second native asset A post-condition for On Other question: What happens with the approval/transfer-rights after a transfer? |
Does the issue raised by @LNow
There is nothing in the nft-trait or nft-transfer function that enforces rules like the nft owner to be the tx-sender - this is down to the implementing contract no? So the rules on transfer come down to the contract author. The approvals have to be reset in the transfer - in the same way the implementation of transfer ensures only the tx-sender/contract-caller is the owner (or approval). |
All very valid thoughts @friedger and @radicleart. Would a basic (define-constant err-unknown-token (err u3))
(define-constant err-not-authorised (err u100))
(define-non-fungible-token stacksies uint)
(define-map approvals {owner: principal, operator: principal, token-id: uint} bool)
(define-public (set-approved (operator principal) (token-id uint) (approved bool))
(ok (map-set approvals {owner: tx-sender, operator: operator, token-id: token-id} approved))
)
(define-read-only (is-approved (token-id uint) (owner principal))
(or
(is-eq owner tx-sender)
(is-eq owner contract-caller)
(default-to false (map-get? approvals {owner: owner, operator: tx-sender, token-id: token-id}))
(default-to false (map-get? approvals {owner: owner, operator: contract-caller, token-id: token-id}))
)
)
(define-public (transfer (token-id uint) (sender principal) (recipient principal))
(begin
(asserts! (is-approved token-id (unwrap! (nft-get-owner? stacksies token-id) err-unknown-token)) err-not-authorised)
(nft-transfer? stacksies token-id sender recipient)
)
) But it would be a lot nicer if ;; Pseudo-code
;; (guard (list post-condition) expression)
;; (stx-post-condition amount sender recipient)
(guard
(list (stx-post-condition u100 (as-contract tx-sender) tx-sender))
(as-contract (contract-call? ...))
) Still, there are situations where malicious contracts can still do unwanted contract calls. Another alternative would be to additionally specify which contracts are allowed to be called in a contract call by means of a post condition. For example: a contract call to Then there was also a related discussion brought up in the Discord channels before: it would be great if we could write post conditions that assert custom Excuse the segue 😁. |
Marvin, and the transfer must/should also...
|
@radicleart rationale? Maybe the user will receive the token back at some point and wants to keep the operator approved. I would prefer not to implicitly remove approval, as it is basically making a choice on the user's behalf. |
The transfer is passing ownership to a new user who may not approve the previous owners operator. Ah - i see the original owner is in the map - ok i get it. |
Does having
in is-approved expose the contract to the hack of the method being called by an intermediary contract? as in this issue.. stacks-network/stacks-core#2921 |
My rough idea how we could tackle approvals and transfers. (define-non-fungible-token Token uint)
(define-non-fungible-token TokenApproval {
owner: principal,
operator: principal,
tokenId: uint,
transfersCount: uint,
})
;; tokenId
;; transfers count (cnt)
(define-map TransfersCount uint uint)
(define-read-only (get-transfers-count (tokenId uint))
(default-to u0 (map-get? TransfersCount tokenId))
)
(define-public (grant-approval (tokenId uint) (operator principal))
(let
(
(transfersCount (get-transfers-count tokenId))
(approvalId {owner: tx-sender, operator: operator, tokenId: tokenId, transfersCount: transfersCount})
)
(try! (nft-mint? TokenApproval approvalId tx-sender))
(try! (nft-transfer? TokenApproval approvalId tx-sender operator)) ;; require post-conditions
(ok true)
)
)
(define-public (transfer (tokenId uint) (sender principal) (recipient principal))
(let
(
(owner (unwrap! (nft-get-owner? Token tokenId) (err u99999)))
(transfersCount (get-transfers-count tokenId))
(approvalId {owner: owner, operator: tx-sender, tokenId: tokenId, transfersCount: transfersCount})
(isApproved (is-some (nft-get-owner? TokenApproval approvalId)))
)
(asserts! (or (is-eq tx-sender owner) isApproved) (err u99999999))
(if isApproved
(try! (nft-burn? TokenApproval approvalId tx-sender))
true
)
(map-set? TransfersCount tokenId (+ transfersCount u1))
(nft-transfer? Token tokenId sender recipient)
)
)
I agree with you @MarvinJanssen but it needs to be defined explicitly. Eg. |
@radicleart sure but contracts would (should) no longer need to do |
@MarvinJanssen Does it mean that we have one listing contract that manage all exchanges? Following the permission token concept that contract would be a huge honeypot for permission tokens, wouldn't it? A proposal for such a solution would be below. What should the parameters for
Alternative |
Maybe there is space for both |
Should there be an overridden list-item that also sets the operator ?
from a usability perspective this would equate to a t&c like checkbox where the user can decide in a single tx to list and authorise a particular operator. |
Minor point here (and sorry if I'm missing something obvious) but in the original proposal, why is specifying the commission explicitly in the If the latter, it probably needs to be called out explicitly for frontends to be careful about which |
The commission trait is necessary to actually call the functions on the trait. Indeed, the frontend and the user should understand the contracts passed in. In particular, appropriate post conditions needs to be added. |
@radicleart I have created two new issues:
|
This sips is about standardizing smart contract functions that enables digital assets to contain ability to participate in an open, decentralized market place.
Owners of NFTs (SIP9) and FTs (SIP10) should be able to list and unlist their token. Buyers should be able to buy the assets from the owner.
A simple trait would look like this:
Marketplaces would observe the list, unlist events and update their inventory accordingly. They act mainly off-chain.
Commission allows to implement royalties for artist on NFTs or fee for marketplaces or different sales mechanims like auctions.
The text was updated successfully, but these errors were encountered: