rmrk-tools icon indicating copy to clipboard operation
rmrk-tools copied to clipboard

Security considerations for LIST / BUY

Open Swader opened this issue 4 years ago • 4 comments
trafficstars

When minting, race conditions don't really matter or happen. However, with the upcoming LIST / BUY functionality, any UI displaying a list of NFTs for sale has no idea if someone has already issued a transaction towards it. This can lead to several purchases for a single NFT, where it would be the seller's responsibility to refund those whose purchases did not go through. We can't really count on people's goodness here, so two solutions are possible:

  1. Use a centralized DB and communicate through it with the UI.
  • Pros:
    • Easy to quickly disable / remove an item that's being purchased
    • Might work faster than a chain-native solution
  • Cons:
    • Might crash during high demand periods.
    • Centralized
    • ?

  1. Add a "centralized" relayer of websockets through which all the different decentralized (IPFS / local) UIs will communicate with each other. The only purpose of this relayer would be to recognize when a TX is in progress for a certain item and to disable that item in other UIs.
  • Pros:
    • More decentralized than the above option
  • Cons:
    • Need to implement in such a way that the WS emitter checks the API connection for Kusama, the TX for a pending one, and makes sure the TX exists in the nodes the other UIs have connected to, for safety.
    • Even with the above, someone ~might~ will figure out how to send bogus WS messages and block UI for everyone else, effectively hoarding all the items.
    • Still has a central element

  1. Add a pending and non-finalized BUY watcher, which would disable an item if it detects a BUY for it in the mempool or an unfinalized block, and put it back if the tx is dropped or the block is forked out.
  • Pros:
    • Decentralized
  • Cons:
    • Hard to reliably implement?

Swader avatar Mar 03 '21 10:03 Swader

Yea was expecting this race condition.

If we're still playing with thesis "all UI need to obey" which we are, things can go wrong on so many levels.. first I can think of looking for finalized block but what if someone submit tx and it was already sold on background meanwhile till user loads and decides, no-one will return that money back. We can double-check just before signing and broadcasting tx if art is still on sale. OR We can come up with some lock period for particular buyer, like handshake window for lockup period (time) which is dedicated to particular buyer, here i can brainstorm more on stake on art which we've been exploring in past and have some knowledge there

4. Dedicated time window for heavily interested buyer.

yangwao avatar Mar 03 '21 11:03 yangwao

another option could be treating "LIST"/"BUY" as just another form of (pay-to-bid) auction, specifically a first-bid-wins auction, where every purchaser makes a bid to purchase - the winner simply wins the right to make the purchase in some range of future blocks - in scenarios of low liquidity, these two operations can happen in the same batch, at the behest of potential purchasers, but in periods of high liquidity, they may wish to split their bid into one block and see if they have won before paying the full BUY price.

jam10o-new avatar Mar 03 '21 11:03 jam10o-new

I have limited understanding still, but so far I like the idea of using something like mempool listener to keep track of pending treansactions to double check pending remarks

https://github.com/protofire/polkadot-mempool-explorer/blob/main/api/services/polkadot/index.js#L224

Although it's not 100% guarantee I think

Yuripetusko avatar Mar 03 '21 11:03 Yuripetusko

So option 3, yeah. It would need to reliably read the mempool AND the unfinalized blocks, recognize IDs and remove them from the UI. I don't know how robust nodes are against a barrage of RPC calls of this type though.

Swader avatar Mar 03 '21 12:03 Swader