Unit ID
PjhrXGUPTbW86mx6IypkVg1RARGIThUKB/efed9oM+Q=
Received
02.06.2021 15:01:57
Confirmation delay (full node)
3 minutes 25 seconds
Confirmation delay (light node)
5 minutes 30 seconds
Messages
Definition
Definition: [ "autonomous agent", { "bounce_fees": { "base": 10000 }, "init": "{ $HOUSE_CUT = 0.1; //We will take this cut on the debut of an NFT in our platform. We charge 0.1% for foreign NFTs. $FREEMARKET_CUT = 0.01; //We take 1% on every non-verified NFT trade $ARTIST_CUT = 0.01; //The artist will get 1% from every resale of their NFT $INVESTMENT_CUT = 0.01; //We take a 1% cut from all maecenas investments $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 = "X56TOFFTFUMMMHDMZPIE5JVFOAX6DRAU"; $CURRENCY_REGISTRY = "MQM63WOOUTTVYBOBWLRJ7LYYUJ5GHMAP"; $extendDeadLine = $NFT=>($NFT.soldAt <= timestamp + $HALF_HOUR) ? ($NFT || {soldAt: $NFT.soldAt + $HALF_HOUR}) : $NFT; //Extend the auction if there is a bid less than half an hour before the auction is closed /* ** Strips $NFT of computed fields to reduce AA's storage size */ $stripToken = $NFT=>{ delete($NFT, "isBanned"); delete($NFT, "cap"); delete($NFT, "mintedAt"); return $NFT; }; 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["owner"]; $calculateSharesToBuy = ($price, $pool, $myShare)=>ln($price / ($pool * $myShare)) / ln($myShare); $_maecenasCurve = $x=>6969420 * $x^2; }", "getters": "{ $saleInfo = $NFT=>{ $unit = unit[$NFT]; $info = var["FREE_" || $NFT] OTHERWISE var["NFT_" || $NFT]; if (NOT $info) bounce("That NFT is not for sale or does not exist"); return $info || { cap: $unit.messages[[.app="asset"]]["payload"]["cap"], mintedAt: $unit.timestamp }; }; /* ** Example of a meta getter to enable platform interop */ $getNFTInfo = $NFT=>{ $unit = unit[$NFT]; /* ** Info should have at least 'author' field. 'ipfs' and 'type' field are also recommended. */ $info = var["FREE_" || $NFT] OTHERWISE var["NFT_" || $NFT]; $transferrable = $unit.messages[[.app="asset"]]["payload"]["transferrable"]; return $info || { cap: $unit.messages[[.app="asset"]]["payload"]["cap"], mintedAt: $unit.timestamp, transferrable: $transferrable }; }; }", "messages": { "cases": [ { "if": "{ NOT $owner }", "messages": [ { "app": "state", "state": "{ var["owner"] = "IUU43O7TS2TBYKAPGKUARDZHOTAE275A"; //Set the Owner to my address var["helper"] = "IUU43O7TS2TBYKAPGKUARDZHOTAE275A"; var["locked"] = 0; //Bytes locked in bids are not withdrawable by the Owner }" } ] }, { "if": "{ trigger.address == $owner AND ($method == "payout" OR $method == "transferOwnership" OR $method == "setHelper") }", "messages": { "cases": [ { "if": "{ $method == "payout" }", "messages": [ { "app": "payment", "payload": { "asset": "base", "outputs": [ { "address": "{trigger.address}", "amount": "{$spendableFunds}" } ] } } ] }, { "if": "{ $method == "transferOwnership" }", "init": "{ if (NOT trigger.data["newOwner"]) bounce("newOwner field is mandatory"); if (NOT is_valid_address(trigger.data["newOwner"])) bounce("newOwner field is not a valid address"); }", "messages": [ { "app": "payment", "payload": { "asset": "base", "outputs": [ { "address": "{trigger.address}", "amount": "{$spendableFunds}" } ] } }, { "app": "state", "state": "{ var["owner"] = trigger.data["newOwner"];//Ownership is transferred }" } ] }, { "if": "{ $method == "setHelper" }", "init": "{ if (NOT trigger.data["helper"]) bounce("helper field is mandatory"); }", "messages": [ { "app": "state", "state": "{ var["helper"] = trigger.data["helper"]; }" } ] } ] } }, { "if": "{ $method == "REGISTER" }", "init": "{ if (NOT exists(trigger.data["NFT"])) bounce("That NFT does not exist"); $definer = unit[trigger.data["NFT"]].authors[0]; if (NOT $definer) bounce("NFT field is not a known asset"); $meta = var[$definer]["NFT"]; //The NFT asset must be defined by the AA that holds its metadata if (NOT $meta) bounce("That NFT platform does not hold its metadata in a format compatible with ours"); }", "messages": [ { "app": "state", "state": "{ var["FREE_" || trigger.data["NFT"]] = $meta; }" } ] }, { "if": "{ (trigger.address == $owner OR trigger.address == var["helper"]) AND $method == "revoke" }", "init": "{ if (NOT trigger.data["NFT"]) bounce("NFT field is mandatory"); }", "messages": [ { "app": "data_feed", "payload": { "{trigger.data["NFT"]}": "REVOKED" } } ] }, { "if": "{ $method == "MINT" }", "init": "{ if (NOT trigger.data["amount"]) bounce("amount field is mandatory"); if (NOT is_valid_amount(trigger.data["amount"]) AND trigger.data["amount"] != 0) bounce("The amount of NFT copies to mint is not valid"); if (NOT trigger.data["type"]) bounce("type field is mandatory"); if (trigger.data["endTime"]){ if (trigger.data["endTime"] <= timestamp) bounce("The endTime cannot be set in the past"); } if ($owner != trigger.address){ //The owner reserves the right to post sales with longer deadlines if (trigger.data["endTime"] - timestamp > 2628000) //A bit more than 30 days bounce("You cannot set the end time in more than 30 days in the future"); } if (NOT trigger.data["title"]) bounce("title field is mandatory"); if (NOT trigger.data["ipfs"]) bounce("ipfs field is mandatory"); if (trigger.data["royalty"]){ if (NOT is_integer(trigger.data["royalty"])) bounce("royalty must be an integer"); if (trigger.data["royalty"] < 0 OR trigger.data["royalty"] > 40) bounce("royalty must be in the interval 0-40"); } $seller = trigger.address == $owner ? trigger.data["seller"] OTHERWISE trigger.address : trigger.address; if (trigger.data["seller"] AND NOT is_valid_address(trigger.data["seller"])) //The owner has to specify who sells the NFT bounce("The seller address is not valid"); $currency = $CURRENCY_REGISTRY.$getCurrency(trigger.data["currency"]); if (trigger.data["currency"]){ if (trigger.data["amount"] == 1) bounce("You cannot price an auction in other than Bytes"); if (NOT $currency) bounce("The provided currency is not supported"); } $prof = $USER_REGISTRY_ADDRESS.$profileOf($seller); $key = $prof.verified ? "NFT_" : "FREE_"; }", "messages": { "cases": [ { "if": "{ trigger.data["amount"] == 1 }", "messages": [ { "app": "asset", "payload": { "cap": 1, "is_private": false, "is_transferrable": true, "auto_destroy": false, "fixed_denominations": false, "issued_by_definer_only": true, "cosigned_by_definer": false, "spender_attested": false } }, { "app": "data", "if": "{ var["recordToData"] }", "payload": { "asset": "{var["recordToData"]}", "name": "{trigger.data["title"] OTHERWISE "Untitled"}", "author": "{$seller}", "ipfs": "{trigger.data["ipfs"]}", "type": "{trigger.data["type"]}", "decimals": 0 } }, { "app": "state", "state": "{ var[$key || response_unit] = { bid: 20000, //Max current bid (a NFT can have this field because it was resold. Check for price field instead) bids: 0, type: trigger.data["type"], by: $seller, royalty: trigger.data["royalty"] OTHERWISE 0, at: timestamp, //Max bid time ipfs: trigger.data["ipfs"], //Hash of the content author: $seller, //The original seller soldAt: trigger.data["endTime"] OTHERWISE timestamp + $ONE_MONTH, //End of the auction soldBy: $seller //Who is currently selling the NFT }; var["recordToData"] = response_unit; }" } ] }, { "init": "{ $price = trigger.data["price"]; if (NOT $price) bounce("price field is mandatory if you intend to sell more than one NFT copy"); if (NOT exists(trigger.data["currency"])){ if ($price < 20000) bounce("The minium price is 20000 bytes"); if (NOT is_valid_amount($price)) //Must be integer for bytes bounce("price is not valid"); } }", "messages": [ { "app": "asset", "if": "{ trigger.data["amount"] == 0 //Uncapped asset, no more units can be issued after endTime }", "payload": { "is_private": false, "is_transferrable": true, "auto_destroy": false, "fixed_denominations": false, "issued_by_definer_only": true, "cosigned_by_definer": false, "spender_attested": false } }, { "app": "asset", "if": "{ trigger.data["amount"] > 0 }", "payload": { "cap": "{trigger.data["inflation"] ? trigger.data["cap"] OTHERWISE 9e15 : trigger.data["amount"]}", "is_private": false, "is_transferrable": true, "auto_destroy": false, "fixed_denominations": false, "issued_by_definer_only": true, "cosigned_by_definer": false, "spender_attested": false } }, { "app": "state", "state": "{ var[$key || response_unit] = { price: $price, //Sale price (this field is only present if the first sale was a fixed price one) type: trigger.data["type"], at: timestamp, royalty: trigger.data["royalty"] OTHERWISE 0, //Max bid time ipfs: trigger.data["ipfs"], //Hash of the content unitsSold: 0, author: $seller, //The original seller soldAt: trigger.data["endTime"] OTHERWISE timestamp + $ONE_MONTH, //End of the auction soldBy: $seller, //Who is currently selling the NFT redeem: trigger.data["redeem"] ? true : false, currency: trigger.data["currency"] OTHERWISE false }; }" } ] } ] } }, { "if": "{ $method == "BUY" OR $method == "CLAIM" }", "init": "{ $NFT = $saleInfo(trigger.data["NFT"]); $artist = $USER_REGISTRY_ADDRESS.$artistInfoOf($NFT.author); if ($method == "BUY"){ //Validate buy params if (NOT exists(trigger.data["NFT"])) bounce("NFT field is mandatory"); $isAuction = $NFT.bid ? true : false; //It can only NOT be an auction if it is first sold and thus $NFT.bid does not exist if ($isAuction) $hasBidders = ($NFT.soldBy != $NFT.by) ? true : false; //Booleans cannot be compared if ($isAuction AND NOT $NFT.by) bounce("There are no copies of that NFT listed for sale at the moment"); if ($isAuction){ if (timestamp > $NFT.soldAt){ if ($isAuction){ if ($hasBidders) //You can still bid on an auction it if there were no bidders bounce("The auction is over"); } else{ bounce("The sale is already over"); } } } } else if ($method == "CLAIM"){ //Validate claim params if (NOT trigger.data["NFT"]) bounce("NFT field is mandatory"); $isAuction = $NFT.bid ? true : false; if (NOT $isAuction) bounce("You cannot claim a non-auction sale"); $hasBidders = ($NFT.soldBy != $NFT.by) ? true : false; if (timestamp <= $NFT.soldAt) bounce("The auction is not over yet"); if ($NFT.claimed) bounce("That auction was already claimed"); } if ($artist AND (($isAuction AND $hasBidders) OR (NOT $isAuction))){ $allowsMaecenas = ($artist.sharePercent >= 0.01) ? true : false; $hasMaecenas = $allowsMaecenas ? $artist.supply > 0 ? true : false : false; if ($allowsMaecenas){ if ($method == "BUY") $maecenasShare = floor($artist.sharePercent * trigger.output[[asset="base"]].amount, 0); else if ($method == "CLAIM" AND $hasBidders) $maecenasShare = floor($artist.sharePercent * $NFT.bid, 0); else $maecenasShare = 0; $sharesInThePool = ($method != "DIVEST") ? $artist.supply : ($artist.supply - trigger.data["amount"]); //If divesting we need to substract divested shares if ($method == "DIVEST") $p = $artist.share - floor((trigger.data["amount"] / $artist.supply) * $artist.share, 0); //Current share minus what was just divested else $p = $artist.share + $maecenasShare; //Pool value after the sale $k = 1 / ($sharesInThePool + 1); //The fraction of the pool 1 share represents $price = $_maecenasCurve($sharesInThePool + 1); //Price of buying one share if ($method == "BUY"){ if ($NFT.soldBy == $NFT.author){ //We do not need to check for auction as we do not invest in those until the claim phase $totalSpendable = floor( $spendableFunds + $price * $INVESTMENT_CUT //What I save from investment cut as it is paid to myself + floor(trigger.output[[asset="base"]].amount * $HOUSE_CUT, 0) //What I got as cut from the triggering tx , 0); } else{ $totalSpendable = floor( $spendableFunds + $price * $INVESTMENT_CUT //What I save from investment cut as it is paid to myself - trigger.output[[asset="base"]].amount //Cannot spend the trigering tx as it will be locked , 0); } } else if ($method == "CLAIM"){ $totalSpendable = floor( $spendableFunds //Initial amount + $price * $INVESTMENT_CUT //What I save from investment cut + $NFT.bid * (1 - $HOUSE_CUT) //What I get from house cut , 0); } else{ $totalSpendable = floor($spendableFunds + $price * $INVESTMENT_CUT, 0); } $sharesToBuy = $sharesInThePool == 0 ? 0 : ceil($calculateSharesToBuy($price, $p, $k), 0);//Can be 0 and I would still afford 1 share if profitable if ($k == 1){ $sharesICanAfford = $price < $totalSpendable ? 1 : 0; } else { if ($totalSpendable > $price AND $sharesToBuy >= 1){ $sharesICanAfford = floor($totalSpendable / ($price * $sharesToBuy * (1 - $INVESTMENT_CUT)), 0); //Do not buy more shares than what I can afford } else{ $sharesICanAfford = 0; } } } if ($allowsMaecenas AND $sharesICanAfford > 0){ $buyShares = true; } else{ $buyShares = false; } $shareIWillfinallyBuy = min($sharesToBuy, $sharesICanAfford); //Maybe I can afford more shares than what is profitable to buy $myProfit = floor($buyShares ? $p - $p * $k^$shareIWillfinallyBuy : 0, 0); //0 if no shares are bought $poolFinalValue = $p - $myProfit; //Not actual profit but what I got out of the pool } else { $allowsMaecenas = false; $buyShares = false; $hasMaecenas = false; $maecenasShare = 0; $myProfit = 0; $poolFinalValue = 0; } }", "messages": { "cases": [ { "if": "{ trigger.data["method"] == "BUY" }", "messages": { "cases": [ { "if": "{ $isAuction }", "init": "{ if (trigger.output[[asset="base"]].amount < 20000) bounce("The minimum bid is 20000 bytes"); if (trigger.output[[asset="base"]].amount <= $NFT.bid * (1 + $MIN_BID_INCREMENT)) bounce("Your bid must be at least " || $NFT.bid * (1 + $MIN_BID_INCREMENT) || " (0.01% higher than the current)"); if ($NFT.soldBy == trigger.address) bounce("You cannot bid on your own auction"); }", "messages": [ { "app": "payment", "if": "{ $NFT.by != $NFT.soldBy //If we don't check for this the artists could steal bytes from the AA }", "payload": { "asset": "base", "outputs": [ { "address": "{$NFT.by}", "amount": "{$NFT.bid - 10000}" } ] } }, { "app": "state", "state": "{ var["locked"] += trigger.output[[asset="base"]].amount - ($hasBidders ? $NFT.bid : 0); //Increase non-withdrawable funds by the difference between previous and last bid $NFT.bid = trigger.output[[asset="base"]].amount; $NFT.at = timestamp; $NFT.bids = $NFT.bids + 1; $NFT.by = trigger.address; if (var["FREE_" || trigger.data["NFT"]])//We do not extend the deadline of freemarket NFTs var["FREE_" || trigger.data["NFT"]] ||= $stripToken($NFT); else var["NFT_" || trigger.data["NFT"]] ||= $stripToken($extendDeadLine($NFT)); }" } ] }, { "init": "{ if ($NFT.unitsSold == $NFT.cap AND $NFT.cap != 0) //We need to make an additional check for uncapped assets bounce("All NFT copies have been already sold"); $realPrice = $NFT.currency ? $CURRENCY_REGISTRY.$getExchangeRate($NFT.currency) * $NFT.price : $NFT.price; response["realPrice"] = $realPrice; response["rate"] = $CURRENCY_REGISTRY.$getExchangeRate($NFT.currency); if (trigger.output[[asset="base"]].amount < $realPrice) bounce("Your payment is lower than the NFT price. You have to send " || $realPrice || " bytes"); }", "messages": [ { "app": "payment", "if": "{ floor($realPrice * (1 - $HOUSE_CUT - ($allowsMaecenas ? (($hasMaecenas OR $buyShares) ? $artist.sharePercent : 0) : 0)) - 10000, 0) > 0 }", "payload": { "asset": "base", "outputs": { "cases": [ { "if": "{ $hasMaecenas }", "outputs": [ { "address": "{$NFT.soldBy}", "amount": "{floor($realPrice * (1 - $HOUSE_CUT - ($allowsMaecenas ? (($hasMaecenas OR $buyShares) ? $artist.sharePercent : 0) : 0)) - 10000, 0)}" }, { "address": "{$USER_REGISTRY_ADDRESS}", "amount": "{$poolFinalValue - $artist.share}" } ] }, { "outputs": [ { "address": "{$NFT.soldBy}", "amount": "{floor($realPrice * (1 - $HOUSE_CUT - ($allowsMaecenas ? (($hasMaecenas OR $buyShares) ? $artist.sharePercent : 0) : 0)) - 10000, 0)}" } ] } ] } } }, { "app": "payment", "payload": { "asset": "{trigger.data['NFT']}", "outputs": [ { "address": "{trigger.address}", "amount": 1 } ] } }, { "if": "{ $hasMaecenas }", "app": "data", "payload": { "share": "{$poolFinalValue - $artist.share}" } }, { "app": "state", "state": "{ if ($NFT.soldBy == $NFT.author){ //Only increase the count if sold by the author if (var["FREE_" || trigger.data["NFT"]]) var["FREE_" || trigger.data["NFT"]] ||= {unitsSold: $NFT.unitsSold + 1}; else var["NFT_" || trigger.data["NFT"]] ||= {unitsSold: $NFT.unitsSold + 1}; //Check if all units were just sold if ($NFT.unitsSold + 1 == $NFT.cap AND $NFT.cap != 0){ if (var["FREE_" || trigger.data["NFT"]]) var["FREE_" || trigger.data["NFT"]] ||= {bid: 0, price: false, soldAt: timestamp, currency: false}; //All units are sold, let's adjust soldAt so it can be already resold else var["NFT_" || trigger.data["NFT"]] ||= {bid: 0, price: false, soldAt: timestamp, currency: false}; //Prepare for auction and delist it from normal sale } } //if ($hasMaecenas){ // var["locked"] += $maecenasShare - $myProfit; // var["artist_" || $NFT.author] ||= {share: $poolFinalValue}; //} }" } ] } ] } }, { "if": "{ trigger.data["method"] == "CLAIM" }", "messages": { "cases": [ { "if": "{ $NFT.soldBy == $NFT.author }", "init": "{ if ($hasMaecenas OR $buyShares){ $paymentFromShares = $shareIWillfinallyBuy * round($price * (1 - $INVESTMENT_CUT), 0); $sellerPayout = floor($NFT.bid * (1 - $HOUSE_CUT - $artist.sharePercent) - 10000 + $paymentFromShares, 0); } else { $sellerPayout = floor($NFT.bid * (1 - $HOUSE_CUT) - 10000, 0); } }", "messages": [ { "app": "payment", "if": "{ $sellerPayout > 0 //enough to be worth paying AND $NFT.soldBy != $NFT.by //there is at least a bid }", "payload": { "asset": "base", "outputs": [ { "address": "{$NFT.soldBy}", "amount": "{$sellerPayout}" } ] } }, { "app": "payment", "payload": { "asset": "{trigger.data['NFT']}", "outputs": [ { "address": "{$NFT.by}", "amount": 1 } ] } }, { "if": "{ $hasMaecenas AND $NFT.bid > 20000 //If it does not have maecenas but accepts them pool is not increased }", "app": "data", "payload": { "share": "{$maecenasShare}" } }, { "app": "state", "state": "{ $decrement = $hasMaecenas //My share does not play a role here ? $NFT.bid - $maecenasShare //If it had maecenas the maecenas share remains locked : $NFT.bid; //If it does not have maecenas all bytes are unlocked if ($NFT.bid > 20000) //If it had no bids you don't need to reduce locked amount var["locked"] -= $decrement; //These bytes are no longer locked as the artist is getting them in this same unit if (var["FREE_" || trigger.data["NFT"]]) var["FREE_" || trigger.data["NFT"]] ||= {claimed: true}; else var["NFT_" || trigger.data["NFT"]] ||= {claimed: true}; //No longer listed for sale //if ($hasMaecenas AND $NFT.bid > 20000) // var["artist_" || $NFT.author] ||= {share: $artist.share + $maecenasShare}; //Increase the artist pool value }" } ] }, { "messages": [ { "app": "payment", "if": "{ $NFT.soldBy != $NFT.by //If we don't do this check the seller could steal bytes from the AA if there were no bids }", "init": "{ $share = $NFT.bid * (1 - $HOUSE_CUT); if ($NFT.royalty > 0 AND $NFT.soldBy != $NFT.by){ $royalty = $share * $NFT.royalty / 100; $outputs = [ {//Royalty address: $NFT.author, amount: floor($royalty, 0) //Percentage of the whole bid, no fees are charged }, {//Seller payment address: $NFT.soldBy, amount: floor($share - $royalty, 0) //We take the house cut then royalty cut } ]; } else{ $outputs = [ {//Seller payment address: $NFT.soldBy, amount: floor($share, 0) } ]; } $payload = {outputs: $outputs}; }", "payload": "{$payload}" }, { "app": "payment", "payload": { "asset": "{trigger.data['NFT']}", "outputs": [ { "address": "{$NFT.by}", "amount": 1 } ] } }, { "app": "state", "state": "{ var["locked"] -= $NFT.bid; if (var["FREE_" || trigger.data["NFT"]]) var["FREE_" || trigger.data["NFT"]] ||= {claimed: true}; else var["NFT_" || trigger.data["NFT"]] ||= {claimed: true}; //No longer listed for sale }" } ] } ] } } ] } }, { "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"); $NFT = $saleInfo($spack.signed_message["NFT"]); if (NOT $NFT) bounce("That NFT does not exist"); //Prevent author from stealing their NFTs from other people if ($NFT.soldBy != $NFT.author) bounce("You cannot claim an NFT that is not being sold by their author"); if ($NFT.author != $spack.authors[0]["address"]) bounce("The signer of that message is not the author of that NFT"); //NFTs have to be created with redeemable: true to be redeemable if (NOT $NFT.redeem) bounce("That NFT is not redeemable"); //Check if sale is over and expire was set in the signed message if ($spack.signed_message["expireDate"]) if ($NFT.soldAt < timestamp OR $spack.signed_message["expireDate"] < timestamp) bounce("That NFT is no longer claimable"); //Check if the NFT is address-locked 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; //Uncapped asset, we can issue whatever amount was signed if (NOT $NFT.cap){ $amount = $signedAmount; } //If it is going over the cap we need to reduce the claimed amount to match the asset cap else { if ($NFT.unitsSold + $signedAmount > $NFT.cap) $amount = $NFT.cap - $NFT.unitsSold; else $amount = $signedAmount; } //All copies were issued if ($amount == 0) bounce("All copies of that NFT have been already minted"); }", "messages": { "cases": [ { "if": "{ trigger.data["NFT"] }", "messages": [ { "app": "state", "state": "{ if (var["FREE_" || trigger.data["NFT"]]) var["FREE_" || trigger.data["NFT"]] ||= {lastBatchDate: timestamp}; else var["NFT_" || trigger.data["NFT"]] ||= {lastBatchDate: timestamp}; }" } ] }, { "messages": [ { "app": "payment", "payload": { "asset": "{$spack.signed_message["NFT"]}", "outputs": [ { "address": "{trigger.address}", "amount": "{$amount}" } ] } }, { "app": "state", "state": "{ if (var["FREE_" || $spack.signed_message["NFT"]]) var["FREE_" || $spack.signed_message["NFT"]] ||= {unitsSold: $NFT.unitsSold + $amount}; else var["NFT_" || $spack.signed_message["NFT"]] ||= {unitsSold: $NFT.unitsSold + $amount}; var["CODE_" || $spack.signed_message["NFT"] || "_" || 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 == "SELL" }", "init": "{ //Parameter validation if (NOT exists(trigger.data["endTime"])) bounce("endTime field is mandatory"); 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 (NOT exists(trigger.data["initialPrice"])) bounce("initialPrice field is mandatory"); if (NOT is_valid_amount(trigger.data["initialPrice"])) bounce("initialPrice must be a valid amount"); if (trigger.data["initialPrice"] < 20000) bounce("The minimum initialPrice is 20000 bytes"); //NFT validation if (trigger.output[[asset!="base"]].asset == "ambigous") bounce("You cannot send more than one NFT type at a time"); //Check that the NFT is not revoked $feedData = data_feed[[oracles=this_address, feed_name=trigger.output[[asset!="base"]].asset, ifnone="OK", ifseveral="last", type="string"]]; if ($feedData == "REVOKED") bounce("We revoked the trading of that token probably due to copyright reasons"); $NFT = $saleInfo(trigger.output[[asset!="base"]].asset) OTHERWISE {}; if (NOT $NFT) bounce("NFT not found"); if (trigger.output[[asset!="base"]].amount != 1) bounce("You cannot auction more than 1 copy of an NFT at a time"); if ($NFT.soldAt >= timestamp)//Booleans cannot be compared if NFT metadata is not present (user tried to sell an asset not issued by this AA) bounce("A copy of that NFT is already being sold. The sale is expected to end at " || timestamp_to_string($NFT.soldAt) || " UTC but may be delayed depending on the number of bids"); if ($NFT.bid AND NOT $NFT.claimed) bounce("That NFT was auctioned but the payment has not been claimed yet. You can force the saller to claim it."); }", "messages": [ { "app": "state", "state": "{ $NFT.bid = trigger.data["initialPrice"]; $NFT.bids = 0; $NFT.by = trigger.address; $NFT.soldBy = trigger.address; $NFT.at = timestamp; $NFT.claimed = false; $NFT.soldAt = trigger.data["endTime"]; if (var["FREE_" || trigger.output[[asset!="base"]].asset]) var["FREE_" || trigger.output[[asset!="base"]].asset] = $stripToken($NFT) || {claimed: false}; else var["NFT_" || trigger.output[[asset!="base"]].asset] = $stripToken($NFT) || {claimed: false}; }" } ] }, { "if": "{ $method == "CHANGE_PRICE" }", "init": "{ if (NOT trigger.data["NFT"]) bounce("NFT field is mandatory"); $NFT = var["NFT_" || trigger.data["NFT"]]; if (NOT $NFT) bounce("NFT not found"); if (NOT trigger.data["price"]) bounce("price field is mandatory"); 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"); if ($NFT.bid) bounce("You cannot change an auction price!"); if (exists(trigger.data["currency"])) //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"); }", "messages": [ { "app": "state", "state": "{ var["NFT_" || trigger.data["NFT"]] ||= {price: trigger.data["price"], currency: trigger.data["currency"] OTHERWISE false}; }" } ] } ] } } ]
Technical information
Fees:
38,981 bytes
(452 headers, 38529 payload)
Level:2029831
Witnessed level:2029824
Main chain index:2021840
Latest included mc index:2021839
Status:stable/confirmed/final