Unit ID
YUNCK630W+bo55/yws64AT82pPAh0qlEOvmmQR7SYTk=
Received
07.08.2021 21:08:11
Confirmation delay (full node)
7 minutes 53 seconds
Messages
Definition
Definition: [ "autonomous agent", { "bounce_fees": { "base": 10000 }, "init": "{ $HOUSE_CUT = var["FEE"]; //We will take this cut on every sale/auction. $HALF_HOUR = 1800; //30m = 1800s. An auction is extended by 1800s every time there is a new bid near the deadline $RESERVE_AMOUNT = 200000; //We will always keep > 200.000 in the AA $MIN_BID_INCREMENT = 0.0001; //Bids must be at least 0.01% higher than the previous one $ONE_MONTH = 2592000; $USER_REGISTRY_ADDRESS = "2NEH2TEG725U3JGJOIE3FCAEGY5HGVFU"; $CURRENCY_REGISTRY = "R4MRGA3MRU33EAWQFX4TBKT6INKWCTHH"; $MAX_ROYALTY = var[$USER_REGISTRY_ADDRESS]["maxRoyalty"]; if (NOT trigger.data["method"]) bounce("method field is mandatory"); $method = trigger.data["method"]; $spendableFunds = balance["base"] - var["locked"] - storage_size - $RESERVE_AMOUNT; $owner = var[$USER_REGISTRY_ADDRESS]["owner"]; if (NOT $owner) bounce("The smart contract has not been initialized yet"); }", "getters": "{ $saleInfo = ($NFT, $seller)=>{ $unit = unit[$NFT]; $info = var["FREE_" || $NFT || "_" || $seller] OTHERWISE var["NFT_" || $NFT || "_" || $seller]; if (NOT $info) bounce("That NFT is not for sale or does not exist"); return $info; }; $fetchNFT = $asset => { $unitInfo = unit[$asset]; $parentUnit = unit[$unitInfo.parent_units[0]]; if (NOT $unitInfo.messages) bounce("Bad unit"); $schema = $unitInfo.authors[0].authentifiers ? false : $unitInfo.authors[0].address; if (NOT $schema) bounce("We can only accept NFTs defined with a schema"); $definedBy = $unitInfo.authors[0].authentifiers ? $unitInfo.authors[0].address //Is a person : $parentUnit.authors[0].address; //Is a person or an AA (they can also define NFTs) $metadata = $parentUnit.messages[[.app='data']].payload; $isAccepted = var["SCHEMA_" || $schema]; if (NOT $isAccepted) bounce("We do not accept NFTs with that schema"); $assetMetadata = $unitInfo.messages[[.app='asset']].payload; return {asset: $assetMetadata, meta: $metadata, author: $definedBy}; }; }", "messages": { "cases": [ { "if": "{NOT $HOUSE_CUT}", "messages": [ { "app": "state", "state": "{ var["locked"] = 0; //Bytes locked in bids are not withdrawable by the Owner var["FEE"] = 0.1; //10% first sale fee }" } ] }, { "if": "{ trigger.address == $owner AND ($method == "payout" OR $method == "transferOwnership" OR $method == "reduceFee" OR $method == "setSchema") }", "messages": { "cases": [ { "if": "{$method == "payout"}", "messages": [ { "app": "payment", "payload": { "asset": "base", "outputs": [ { "address": "{trigger.address}", "amount": "{$spendableFunds}" } ] } } ] }, { "if": "{$method == "reduceFee"}", "init": "{ if (NOT exists(trigger.data["fee"])) bounce("fee field is mandatory"); if (trigger.data["fee"] < 0) bounce("Are you drunk?"); if (trigger.data["fee"] >= $HOUSE_CUT) bounce("fee must be lower than the current one"); }", "messages": [ { "app": "state", "state": "{ var["FEE"] = trigger.data["fee"]; }" } ] }, { "if": "{$method == "setSchema"}", "init": "{ if (NOT trigger.data["schema"]) bounce("schema field is mandatory"); if (NOT is_aa(trigger.data["schema"])) bounce("schema is not the address of an autonomous agent"); }", "messages": [ { "app": "state", "state": "{ var["SCHEMA_" || trigger.data["schema"]] = true; }" } ] } ] } }, { "if": "{$method == "BUY"}", "init": "{ if (NOT trigger.data["address"]) bounce("address field is mandatory"); if (NOT is_valid_address(trigger.data["address"])) bounce("address field is an invalid address"); if (NOT trigger.data["NFT"]) bounce("NFT field is mandatory"); if (trigger.address == trigger.data["address"]) bounce("You are buying your own NFT. Claim it instead in order to avoid fees"); $sale = $saleInfo(trigger.data["NFT"], trigger.data["address"]); $nft = $fetchNFT(trigger.data["NFT"]); $artist = $USER_REGISTRY_ADDRESS.$artistInfoOf($nft.author); $amount = $sale.isAuction ? 1 //1 lot not 1 unit : trigger.data["amount"] OTHERWISE 1; $pricePerUnit = $sale.currency ? $CURRENCY_REGISTRY.$convert($sale.price, $sale.currency) : $sale.price; $fullPrice = $amount * $pricePerUnit; $cut = round($fullPrice * $HOUSE_CUT, 0); $toAuthor = round($fullPrice * (min($nft.meta["royalty"] OTHERWISE 0, $MAX_ROYALTY))/100, 0); response["meta"] = $nft.meta; response["toAuthor"] = $toAuthor; $toSeller = $fullPrice - $cut - $toAuthor - 10000; }", "messages": [ { "if": "{NOT $sale.auction}", "init": "{ if (exists(trigger.data["amount"])){ if (NOT is_integer(trigger.data["amount"])) bounce("amount field must be an integer"); if (trigger.data["amount"] < 1) bounce("amount field must be at least 1"); if (trigger.data["amount"] > $sale.amount) bounce("That user is selling only " || $sale.amount || " units"); } if ($sale.currency) response["rate"] = $CURRENCY_REGISTRY.$getExchangeRate($sale.currency); response["realPrice"] = $pricePerUnit; response["total"] = $fullPrice; if (trigger.output[[asset="base"]].amount < $fullPrice) bounce("Your payment is lower than the NFT price. You have to send " || $fullPrice || " bytes"); }", "app": "payment", "payload": { "asset": "base", "outputs": [ { "address": "{$sale.soldBy}", "amount": "{$toSeller}" }, { "if": "{$toAuthor > 5000}", "address": "{$nft.author}", "amount": "{$toAuthor}" } ] } }, { "if": "{NOT $sale.auction}", "app": "payment", "payload": { "asset": "{trigger.data['NFT']}", "outputs": [ { "address": "{trigger.address}", "amount": "{$amount}" } ] } }, { "app": "state", "state": "{ if ($sale.auction) { if (trigger.output[[asset="base"]].amount < 20000) bounce("The minimum bid is 20000 bytes"); if (trigger.output[[asset="base"]].amount <= $sale.price * (1 + $MIN_BID_INCREMENT)) bounce("Your bid must be at least " || ceil($sale.price * (1 + $MIN_BID_INCREMENT), 0) || " (0.01% higher than the current)"); if ($sale.soldBy == trigger.address) bounce("You cannot bid on your own auction"); if (timestamp > $sale.endTime AND $sale.bids) //You can still bid on an expired auction if it had no bids. This will reawake the bid for 30 mins if the NFT was created by an attested user. Otherwise you will be able to claim the auction right away after bidding. bounce("The auction is over"); var["locked"] += trigger.output[[asset="base"]].amount - ($sale.by ? $sale.price : 0); //Increase non-withdrawable funds by the difference between previous and last bid $saleState = $sale || { price: trigger.output[[asset="base"]].amount, at: timestamp, bids: $sale.bids + 1, by: trigger.address, endTime: $sale.endTime + $HALF_HOUR }; } else { $newAmount = $sale.amount - $amount; $saleState = $newAmount == 0 ? false : $sale || {amount: $newAmount, at: timestamp}; } $key = var["FREE_" || trigger.data["NFT"] || "_" || trigger.data["address"]] ? "FREE_" : "NFT_"; $fullKey = $key || trigger.data["NFT"] || "_" || trigger.data["address"]; var[$fullKey] = $saleState; }" } ] }, { "if": "{$method == "CLAIM"}", "init": "{ $address = trigger.data["address"] OTHERWISE trigger.address; $sale = $saleInfo(trigger.data["NFT"], $address); if (NOT trigger.data["NFT"]) bounce("NFT field is mandatory"); $nft = $fetchNFT(trigger.data["NFT"]); $artist = $USER_REGISTRY_ADDRESS.$artistInfoOf($nft.author); if (NOT $sale.auction) bounce("That sale is not an auction"); if ($sale.auction AND timestamp <= $sale.endTime) bounce("The auction is not over yet"); $fullKey = var["FREE_" || trigger.data["NFT"] || "_" || $sale.soldBy] ? "FREE_" || trigger.data["NFT"] || "_" || $sale.soldBy : "NFT_" || trigger.data["NFT"] || "_" || $sale.soldBy; }", "messages": { "cases": [ { "if": "{$sale.auction}", "messages": [ { "if": "{$sale.bids > 0}", "app": "payment", "init": "{ $share = $sale.price * (1 - $HOUSE_CUT); if ($nft.meta["royalty"]){ $royalty = $sale.price * min($nft.meta["royalty"], $MAX_ROYALTY) / 100; $outputs = [ {//Royalty address: $nft.author, amount: floor($royalty, 0) //Percentage of the whole bid, no fees are charged }, {//Seller payment address: $sale.soldBy, amount: floor($share - $royalty, 0) //We take the house cut then royalty cut } ]; } else{ $outputs = [ {//Seller payment address: $sale.soldBy, amount: floor($share, 0) } ]; } $payload = {outputs: $outputs}; }", "payload": "{$payload}" }, { "app": "payment", "payload": { "asset": "{trigger.data['NFT']}", "outputs": [ { "address": "{$sale.by OTHERWISE $sale.soldBy}", "amount": "{$sale.amount}" } ] } }, { "app": "state", "state": "{ if ($sale.bids > 0) //If it had no bids you cannot reduce locked amount var["locked"] -= $sale.price; var[$fullKey] = false; //No longer listed for sale }" } ] }, { "if": "{NOT $sale.auction}", "init": "{ if (trigger.address != $sale.soldBy) bounce("You cannot claim other people's sales"); }", "messages": [ { "app": "payment", "payload": { "asset": "{trigger.data['NFT']}", "outputs": [ { "address": "{$sale.soldBy}", "amount": "{$sale.amount}" } ] } }, { "app": "state", "state": "{ var[$fullKey] = false; }" } ] } ] } }, { "if": "{$method == "CHANGE_PRICE"}", "init": "{ if (NOT trigger.data["NFT"]) bounce("NFT field is mandatory"); $sale = $saleInfo(trigger.data["NFT"], trigger.address); if (NOT $sale) bounce("Sale not found"); if (NOT exists(trigger.data["price"])) bounce("price field is mandatory"); if (NOT exists(trigger.data["currency"])){ //Priced in bytes, we cannot allow decimals if (NOT is_integer(trigger.data["price"])) bounce("price must be an integer"); if (NOT is_valid_amount(trigger.data["price"])) bounce("price is invalid"); if (trigger.data["price"] < 20000) bounce("The minimum price is 20000 bytes"); } else{//User wants price to be foreign asset based, let's check if we support the asset if (NOT $CURRENCY_REGISTRY.$getCurrency(trigger.data["currency"])) bounce("You cannot set the price in that currency"); } if ($sale.auction) bounce("You cannot change an auction price!"); }", "messages": [ { "app": "state", "state": "{ if (var["NFT_" || trigger.data["NFT"] || "_" || trigger.address]) var["NFT_" || trigger.data["NFT"] || "_" || trigger.address] ||= {price: trigger.data["price"], soldBy: trigger.address, currency: trigger.data["currency"] OTHERWISE false}; else var["FREE_" || trigger.data["NFT"] || "_" || trigger.address] ||= {price: trigger.data["price"], soldBy: trigger.address, currency: trigger.data["currency"] OTHERWISE false}; }" } ] }, { "if": "{$method == "SELL"}", "init": "{ if (trigger.output[[asset!="base"]].asset == "ambigous") bounce("You can only send a single NFT at a time"); $NFT = $fetchNFT(trigger.output[[asset!="base"]].asset); $prof = $USER_REGISTRY_ADDRESS.$profileOf($NFT.author); if (2NEH2TEG725U3JGJOIE3FCAEGY5HGVFU.$isRevoked(trigger.output[[asset!="base"]].asset)) bounce("We revoked the trading of that token probably due to copyright reasons"); if (NOT trigger.data["price"]) bounce("price field is mandatory"); if (trigger.data["currency"]){ if (NOT $CURRENCY_REGISTRY.$getCurrency(trigger.data["currency"])) bounce("We do not support that currency"); } else { if (NOT is_integer(trigger.data["price"])) bounce("Price must be an integer"); if (NOT is_valid_amount(trigger.data["price"])) bounce("Price is not a valid amount"); if (NOT trigger.data["auction"]){ if (trigger.data["price"] * trigger.output[[asset!="base"]].amount < 20000) bounce("The minimum sale price is 20.000 bytes"); } } if (trigger.data["auction"]){ if (NOT exists(trigger.data["endTime"])) bounce("If you want to hold an auction you have to specify the endTime"); if (trigger.data["price"] < 20000) bounce("Minimum auction price is 20.000 bytes"); if (trigger.data["currency"]) bounce("You cannot set the auction price in other currency than bytes"); if (trigger.data["endTime"] <= timestamp) bounce("You cannot set the end time in the past"); if (trigger.data["endTime"] > timestamp + 2628000) bounce("You cannot set the end time in more than 30 days"); } if (var["FREE_" || trigger.output[[asset!="base"]].asset || "_" || trigger.address] OR var["NFT_" || trigger.output[[asset!="base"]].asset || "_" || trigger.address]) bounce("You already have an open sale or auction for that NFT. Please claim it before starting another one"); }", "messages": [ { "app": "state", "state": "{ $key = ($prof.verified ? "NFT_" : "FREE_") || trigger.output[[asset!="base"]].asset || "_" || trigger.address; var[$key] = { price: trigger.data["price"], amount: trigger.output[[asset!="base"]].amount, endTime: trigger.data["auction"] ? trigger.data["endTime"] : false, soldBy: trigger.address, bids: trigger.data["auction"] ? 0 : false, auction: trigger.data["auction"] ? true : false, currency: trigger.data["auction"] ? '' : trigger.data["currency"] OTHERWISE false }; }" } ] } ] } } ]
Technical information
Fees:
19,628 bytes
(451 headers, 19177 payload)
Level:7969360
Witnessed level:7969353
Main chain index:7652996
Latest included mc index:7652995
Status:stable/confirmed/final