create account

NFT Research - Auctions and Secure Transfer by disregardfiat

View this thread on: hive.blogpeakd.comecency.com
· @disregardfiat ·
$245.64
NFT Research - Auctions and Secure Transfer
### Building Economies

While this is still going to be a technical discussion, we're finally starting to put all of our features to work. Discussion on and off chain has been invaluable to development and these posts serve as thought-ware to help flush out features that make the best product. This post will discuss the mechanics of auctions, a key all-party process to well establish real time values of Non-Fungible Assets in the same way D/C Exchanges are all party process to determine the real time value of fungible assets. 

Continuing from:
* [Building NFTs on Hive](https://peakd.com/hive-139531/@disregardfiat/building-nfts-on-hive)
* [NFT Research - Computation and Storage](https://peakd.com/hive-139531/@disregardfiat/nft-research-computation-and-storage)
* [NFT Research - Attributes and Modifications](https://peakd.com/hive-139531/@disregardfiat/nft-research-attributes-and-modifications)

The above posts contain prototype level code that will continue to be used in this post, so if you haven't strapped in yet, you might fall off the ride. If you're not here for the code and just looking at features and discussion - let's go!

### Auctioning an NFT

Starting with user interface, there might be either a list of your accounts NFTs, or an NFT you are looking at may have an auction button. Which will then have a starting price, and a time. Optionally, a 'Buy Token Now' price could be specified.

Once decided these options will be signed to Hive via a custom json and our layer 2 will pick up the transaction with the following code:
Payload: json.`{set:"punk", uid:"A6", p:1000, t:7}` to list punk:A6 at 1.000 for 7 days 
``` .js
1|exports.nft_auction = function(json, from, active, pc) {
2| let fnftp = getPathObj(['nfts', from]),
3|  ahp = getPathObj(['ah']);
4|  setp = getPathObj(['sets', json.set])
5| Promise.all([fnftp, ahp, setp])
6| .then(mem => {
7|  if (mem[0][`${json.set}:${json.uid}`] && !mem[0][`${json.set}:${json.uid}`].l && active){
8|   var ah = mem[1],
9|    nft = mem[0][`${json.set}:${json.uid}`],
10|    set = mem[2], fnfts = mem[0]
11|   delete fnfts[`${json.set}:${json.uid}`] //remove nft from from
12|   var p = json.p || 1000,
13|    t = json.t || 7
14|   if(typeof t != number || t > 30 || t < 1 )t = 7
15|   if(typeof p != number || p < 1)p = 1000
16|   const e = json.block_num + (json.t * 1200 * 24),
17|    ep = chronAssign(e, {op:"ahe", item:`${json.set}:${json.uid}`, block: e})
18|   ep.then(exp => {
19|    var listing = {
20|     p, //starting price
21|     t, //time in days
22|     e, //expires
23|     x: exp, //expire path / vop
24|     o: from
25|    }
26|    set.u.replace(`${json.uid}_${json.from}`, `${json.uid}_ah`)
27|    var last_modified = nft.s.split(',')[0]
28|    nft.s.replace(last_modified, Base64.fromNumber(json.block_num))
29|    listing.nft = nft
30|    ah[`${json.set}:${json.uid}`] = listing //place the listing in the AH
31|    ops.push([{type:'put', path:['nfts', from], data: fnfts}])
32|    ops.push([{type:'put', path:['ah'], data: ah}])
33|    ops.push([{type:'put', path:['sets', json.set], data: set}])
34|    let msg = `@${from} Listed ${json.set}:${json.uid} for auction`
35|    if (config.hookurl) postToDiscord(msg)
36|    ops.push({ type: 'put', path: ['feed', `${json.block_num}:${json.transaction_id}`], data: msg });
37|    store.batch(ops, pc)
38|   })
39|  } else if (!active){
40|   let msg = `@${from} tried to auction with out signing ACTIVE`
41|   if (config.hookurl) postToDiscord(msg)
42|   pc[0](pc[2])
43|  } else {
44|   let msg = `@${from} doesn't own ${json.set}:${json.uid}`
45|   if (config.hookurl) postToDiscord(msg)
46|   pc[0](pc[2])
47|  }
48| })
49|}
```
* 1: Function name of custom JSON ID `nameOfLayer2_nft_auction`
* 2-4: Uses the custom JSON and payload to call the NFT, Set, and Auction House from the database
* 7: Checks that the active key was used, and that the account owns the NFT, and no lien holder's are present
  * 38-46 Reports any error to a stream, and tells the Process Chain to compute the next transaction
* 11: Removes the NFT from the owners directory
* 12-15: Sets and verifies initial price and days of auction are valid.
* 16: Calculates the last block of the auction
* 17: Build's the Virtual Op that will settle the auction: `ahe`: Auction House End
* 18: Get's the memory location of the `ahe`
* 19-25: Builds the Listing
* 26: Modifies the Set locator from `UniqueID_Owner` to `UniqueID_ah`
* 27-28: Updates the Last Modified of the NFT to the current block number
* 29: Places the NFT is the listing
* 30: Places the Listing in the `ah` directory
* 31-33: Builds a batch memory update to store the above changes
* 34-36: Builds an information string for on chain, and possible off chain streaming
* 37: Sends the batch memory operation to be stored, along with the process chain to start the next transaction in sequence in a memory safe way.

### Bidding in an Auction
Each Node on the layer 2 should be providing identical API to view the listings, so there will be some user interface(s) that will show whats available. This UI should also utilize local storage to keep up on which items you are watching and what you've bid on... so you can tell when you've been outbid.

Below is the code for a bid. Much like in an actual auction, the only available actions are bid.


Payload: json.`{b:1002, set:"punk", uid:"A6"}` bidding 1.002 for  punk:A6
```
1|exports.nft_bid = function(json, from, active, pc) {
2| let balp = getPathNum(['balances', from]),
3|   ahp = getPathObj(['ah', `${json.set}:${json.uid}`])
4|  Promise.all([balp, ahp])
5|  .then(mem => {
6|   if(active && mem[1].p && mem[0] >= json.bid){
7|    var listing = mem[1],
8|     bal = mem[0]
9|    if(listing.b){
10|     if (json.bid > listing.b){
11|      add(listing.f, listing.b)
12|      .then(empty => {
13|       listing.f = from
14|       listing.b = json.bid; listing.c++
15|       bal = bal - json.bid
16|       var ops = []
17|       ops.push([{type:'put', path:['ah', `${json.set}:${json.uid}`], data: listing}])
18|       ops.push([{type:'put', path:['balances', from], data: bal}])
19|       let msg = `@${from} bid ${parseFloat(json.bid/1000).toFixed(3)} ${config.TOKEN} on ${json.set}:${json.uid}'s auction`
20|       if (config.hookurl) postToDiscord(msg)
21|       ops.push({ type: 'put', path: ['feed', `${json.block_num}:${json.transaction_id}`], data: msg });
22|       store.batch(ops, pc)
23|      })
24|     } else {
27|      // low bid message
26|     }
27|    } else {
28|     //roughly the same as above with out return... initial bid
29|    }
30|   } else {
31|    //error msg
34|   }
35|  })
36|}
```
* 1: Function name of custom JSON ID `nameOfLayer2_nft_bid`
* 2-3: Pulls `from`'s balance and the auction house from memory
* 6: Checks that `from` has enough tokens to make the bid, and that the item is up for auction with a lower bid
* 9: Checks for previous bid
* 10: Check `from`'s bid is higher
* 11: Returns the previous high bidder's tokens
* 12->: Updates and saves the Listing and `from`'s balance
* 14: Keeps track of the total number of valid bids
### Ending an Auction
When an auction is over the layer 2 will automatically process the listing and make several balance adjustments. This is done because a Virtual Op was set up at the listing, and every block the processor checks for any operations in memory under the current block number.

```
switch (b.op) {
 case 'ahe':
  let ahp = getPathObj(['ah', b.item]);
   setp = getPathObj(['sets', b.item.split(':')[0]])
  promises.push(AHEOp([ahp, setp], delKey, num, b)) //ensure Vops end before the next transaction is processed
...

function AHEOp(promies, delkey, num, b) {
 return new Promise((resolve, reject) => {
 Promise.all(promies)
 .then(mem => {
  let listing = mem[0],
   set = mem[1],
   ops = []
   // const fee = parseInt(listing.b /100); add('rn', fee); listingb = listing.b - fee;
   if (set.r > 0){
    let royalty = parseInt(listing.b * set.r / 100)
    add(set.a, royalty) //distribute royalty
    add(listing.o, listing.b - royalty) //distribute rest
   } else {
    add(listing.o, listing.b)
   }
   nft = listing.nft
   const last_modified = nft.s.split(',')[0]
   nft.s.replace(last_modified, Base64.fromNumber(num)) //update last modified
   set.u.replace(`${b.item.split(':')[1]}_ah`, `${b.item.split(':')[1]}_${listing.f}`) //update set
   ops.push({ type: 'del', path: ['ah', b.item] }) //delete the listing
   ops.push({ type: 'put', path: ['sets', b.item.split(':')[0]], data: set }) //update set
   ops.push({ type: 'put', path: ['nfts', listing.f, b.item], data: nft }) //update nft
   ops.push({ type: 'put', path: ['feed', `${num}:vop_${delkey.split(':')[1]}`], data: `Auction of ${b.item} has ended for ${parseFloat(listing.b / 1000).toFixed(3)} ${config.TOKEN}` })
   ops.push({ type: 'del', path: ['chrono', delkey] })
   store.batch(ops, [resolve, reject])
  })
...
```
### Summary
You may (or may not, sorry) be able to see we can securely auction these NFTs with minimal code. All the layer 2 nodes run this code and all of the NFTs they can support will be able to change the ownership, pay royalties, and enforce liens. 

Building our features first let's us ensure that our final product will have the ability to expand into these use cases. For example, even if we don't have any code to put a lien holder on an NFT, we can think ahead and not allow a sale, auction, or transfer if a lien holder exists.

And thus far we haven't run in to any snags that won't let us implement our feature set.

Secure Transfers will work in much the same way, except only one party will be able to fulfill the listing.

My last NFT research post is on Minting... now that we've established all our features. That post will of course contain an announcement for a founders/testing set of DLUX tokens.

![😉](https://www.dlux.io/img/dlux-hive-logo-alpha.svg)
👍  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , and 226 others
👎  
properties (23)
authordisregardfiat
permlinknft-research-auctions-and-secure-transfer
categoryhive-139531
json_metadata"{"app":"peakd/2021.09.1","format":"markdown","description":"Secure NFT Auction Code in the goriest possible detail","tags":["hive","dev","dlux","nft","defi"],"users":["disregardfiat"],"image":["https://www.dlux.io/img/dlux-hive-logo-alpha.svg"]}"
created2021-09-16 18:10:18
last_update2021-09-16 18:10:18
depth0
children6
last_payout2021-09-23 18:10:18
cashout_time1969-12-31 23:59:59
total_payout_value122.856 HBD
curator_payout_value122.783 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length9,895
author_reputation315,394,957,585,090
root_title"NFT Research - Auctions and Secure Transfer"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id106,339,746
net_rshares289,409,875,701,256
author_curate_reward""
vote details (291)
@gangstalking ·
Electronic-terrorism, voice to skull and neuro monitoring on Hive and Steem. You can ignore this, but your going to wish you didnt soon. This is happening whether you believe it or not. https://ecency.com/fyrstikken/@fairandbalanced/i-am-the-only-motherfucker-on-the-internet-pointing-to-a-direct-source-for-voice-to-skull-electronic-terrorism
👎  ,
properties (23)
authorgangstalking
permlinkre-disregardfiat-nft-research-auctions-and-secure-transfer-20210916t181024976z
categoryhive-139531
json_metadata{"app":"hive-bot/0.6.3"}
created2021-09-16 18:10:27
last_update2021-09-16 18:10:27
depth1
children0
last_payout2021-09-23 18:10:27
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length343
author_reputation-67,597,107,868,724
root_title"NFT Research - Auctions and Secure Transfer"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id106,339,750
net_rshares-27,854,681,966
author_curate_reward""
vote details (2)
@mlrequena78 ·
I wish everything to be successful
properties (22)
authormlrequena78
permlinkqzlib7
categoryhive-139531
json_metadata{"app":"hiveblog/0.1"}
created2021-09-17 20:30:33
last_update2021-09-17 20:30:33
depth1
children0
last_payout2021-09-24 20:30:33
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length34
author_reputation7,346,493,787,724
root_title"NFT Research - Auctions and Secure Transfer"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id106,365,647
net_rshares0
@pizzabot ·
<div class='pull-right'><center><sup>Connect</sup></center><p><a href="https://discord.gg/Q9bQAKpWGS"><img src="https://files.peakd.com/file/peakd-hive/pizzabot/AKF96fKjnX3wjXERHcKAFHaoHnfTVhXqPjXVz8E1Th9nPiJqmFtaycosVpPBZ7z.png"></a></p></div><div class='pull-right'><center><sup>Trade</sup></center><p><a href='https://hive-engine.com/?p=market&t=PIZZA'><img src="https://files.peakd.com/file/peakd-hive/pizzabot/23sxbi2M4UjELDzQjxPdzubdgfMjHTCtA1xueyxmnhJUrB8136VyK3pqynyWYiZYF9HrC.png"></a></p></div><center><br> <p>@disregardfiat! This post has been manually curated by the <strong><em>$PIZZA</em></strong> Token team!</p><p>Learn more about <strong><em>$PIZZA Token</em></strong> at <a href="https://hive.pizza">hive.pizza</a>. Enjoy a slice of $PIZZA on us!</p> </center><div></div>
properties (22)
authorpizzabot
permlinkre-nft-research-auctions-and-secure-transfer-20210917t013918z
categoryhive-139531
json_metadata"{"app": "beem/0.24.26"}"
created2021-09-17 01:39:18
last_update2021-09-17 01:39:18
depth1
children0
last_payout2021-09-24 01:39:18
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length789
author_reputation5,986,602,450,698
root_title"NFT Research - Auctions and Secure Transfer"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id106,347,043
net_rshares0
@russia-btc ·
Great - but it will take you a very, very long time to implement everything - you may be late!
properties (22)
authorrussia-btc
permlinkqzl21h
categoryhive-139531
json_metadata{"app":"hiveblog/0.1"}
created2021-09-17 14:39:21
last_update2021-09-17 14:39:21
depth1
children2
last_payout2021-09-24 14:39:21
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length94
author_reputation17,815,026,273,177
root_title"NFT Research - Auctions and Secure Transfer"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id106,358,892
net_rshares0
@disregardfiat ·
Netflix was later than Blockbuster. Testing starts soon(TM). 
properties (22)
authordisregardfiat
permlinkre-russia-btc-qzl287
categoryhive-139531
json_metadata{"tags":["hive-139531"],"app":"peakd/2021.09.1"}
created2021-09-17 14:43:24
last_update2021-09-17 14:43:24
depth2
children1
last_payout2021-09-24 14:43:24
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length61
author_reputation315,394,957,585,090
root_title"NFT Research - Auctions and Secure Transfer"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id106,358,969
net_rshares0
@russia-btc ·
$0.09
Nice.
We hope that everything will turn out in time!
👍  
properties (23)
authorrussia-btc
permlinkre-disregardfiat-2021917t21472426z
categoryhive-139531
json_metadata{"tags":["hive-139531"],"app":"ecency/3.0.19-vision","format":"markdown+html"}
created2021-09-17 14:47:03
last_update2021-09-17 14:47:03
depth3
children0
last_payout2021-09-24 14:47:03
cashout_time1969-12-31 23:59:59
total_payout_value0.043 HBD
curator_payout_value0.044 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length52
author_reputation17,815,026,273,177
root_title"NFT Research - Auctions and Secure Transfer"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id106,359,039
net_rshares104,251,625,940
author_curate_reward""
vote details (1)