Unit ID
TtSc+CwyMSzRAA3UanU3oy8vU6G2QR4eh/RhpT6WbTc=
Received
29.07.2021 22:17:02
Confirmation delay (full node)
4 minutes 3 seconds
Confirmation delay (light node)
7 minutes 2 seconds
Messages
Definition
Definition: [ "autonomous agent", { "bounce_fees": { "base": 10000 }, "init": "{ $HOUSE_CUT = var["FEE"]; //We will take this cut on the debut of an NFT in our platform. We charge 0.1% for foreign NFTs. $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 = "XYJQMDGFM4NRL4GPOWYH5FSCB63GWFCJ"; $CURRENCY_REGISTRY = "PQQ3AQYSGJOFYCBEO3GZT2WWQPVPPFB5"; $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 == "REDEEM"}", "init": "{ if (NOT exists(trigger.data["signed_message"])) bounce("signed_message field is mandatory"); if (NOT exists(trigger.data["authors"])) bounce('authors field is mandatory'); if (NOT exists(trigger.data["meta"])) bounce("meta field is mandatory"); $spack = { signed_message: trigger.data["signed_message"], authors: trigger.data["authors"] } || trigger.data["meta"]; if (NOT is_valid_signed_package($spack, $spack.authors[0]["address"])) bounce("The signed message signature is invalid"); if (NOT $spack.signed_message["serial"]) bounce("The signed message does not contains a serial field"); if (NOT $spack.signed_message["NFT"]) bounce("The signer of this message did not include a NFT field"); //Check if the code has already been redeemed if (var["CODE_" || $spack.signed_message["NFT"] || "_" || sha256($spack.signed_message["serial"])]) bounce("That code was already redeemed"); $sale = $saleInfo($spack.signed_message["NFT"], $spack.authors[0]["address"]); if (NOT $sale) bounce("That NFT is not listed for sale"); if ($sale.auction) bounce("You cannot claim a NFT that is being auctioned"); //Check if expire is set in the signed message if ($spack.signed_message["expireDate"]){ if ($spack.signed_message["expireDate"] < timestamp) bounce("That code is no longer redeemable"); } //Check if the code is address-bound if ($spack.signed_message["claimer"]){ if ($spack.signed_message["claimer"] != trigger.address) bounce("You cannot claim that NFT from that address"); } $signedAmount = $spack.signed_message["amount"] OTHERWISE 1; if ($signedAmount > $sale.amount) $amount = $sale.amount; else $amount = $signedAmount; //All copies were sold if ($amount == 0) bounce("All copies of that NFT have been already sold"); }", "messages": { "cases": [ { "messages": [ { "app": "payment", "payload": { "asset": "{$spack.signed_message["NFT"]}", "outputs": [ { "address": "{trigger.address}", "amount": "{$amount}" } ] } }, { "app": "state", "state": "{ $key = var["FREE_" || $spack.signed_message["NFT"] || "_" || $spack.authors[0]["address"]] ? "FREE_" || $spack.signed_message["NFT"] || "_" || $spack.authors[0]["address"] : "NFT_" || $spack.signed_message["NFT"] || "_" || $spack.authors[0]["address"]; var[$key] = ($sale.amount - $amount > 0) ? $sale || {amount: $sale.amount - $amount} : false; var["CODE_" || $spack.signed_message["NFT"] || "_" || $spack.authors[0]["address"] || "_" || sha256($spack.signed_message["serial"], 'base64')] = true; //Hash the serial to prevent the issuer from sending too big serials to bloat state size }" } ] } ] } }, { "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 (XYJQMDGFM4NRL4GPOWYH5FSCB63GWFCJ.$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"] : '', soldBy: trigger.address, bids: trigger.data["auction"] ? 0 : '', auction: trigger.data["auction"] ? true : false, redeem: trigger.data["redeem"] ? true : false, currency: trigger.data["auction"] ? '' : trigger.data["currency"] OTHERWISE false }; }" } ] } ] } } ]
Technical information
Fees:
23,606 bytes
(452 headers, 23154 payload)
Level:2158791
Witnessed level:2158784
Main chain index:2149353
Latest included mc index:2149352
Status:stable/confirmed/final