Unit ID
Y+uY63p9r9VhSeL3PEMr5MjVU7Og7QcAjqBD12PmsVM=
Received
31.03.2021 23:58:59
Confirmation delay (full node)
1 minute 24 seconds
Confirmation delay (light node)
3 minutes 53 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.001; //We take 0.1% on every foreign 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; $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, "issuer"); delete($NFT, "cap"); delete($NFT, "mintedAt"); delete($NFT, "duration"); //For foreign NFTs return $NFT; }; if (NOT exists(trigger.data["method"])) bounce("method field is mandatory"); $spendableFunds = balance["base"] - var["locked"] - storage_size - $RESERVE_AMOUNT; $owner = var["owner"]; $calculateSharesToBuy = ($price, $pool, $myShare)=>ln($price/($pool*$myShare))/ln($myShare); }", "getters": "{ /* DEBUG $_maecenasCurve = $x=>69069420 * $x^2; */ $_maecenasCurve = $x=>20000*$x^2; // TOKEN RELATED GETTERS /* ** All the information about the given NFT sale */ $tokenInfo = $NFT=>{ $unit = unit[$NFT]; $tok = var[$NFT]; if (NOT $tok) bounce("NFT not found"); $feedData = data_feed[[oracles=this_address, feed_name=$NFT, ifnone="false", ifseveral="last", type="string"]]; return $tok || { isBanned: $feedData == "REVOKED" ? true : false, cap: $unit.messages[[.app="asset"]].payload.cap, mintedAt: $unit.timestamp, issuer: asset[$NFT].definer_address, meta: var["meta_" || $NFT] }; }; $saleInfo = $NFT=>{ $unit = unit[$NFT]; $info = 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 }; }; /* ** How many copies of the NFT were sold, bounces if we did not mint the NFT */ $circulatingSupply = $NFT=>{ $info = $tokenInfo($NFT); if ($info.isBanned) bounce("That NFT was revoked"); if ($info.issuer != this_address) bounce("That NFT was not minted by us, thus we don't know how many of them are out in the wild"); return $info.unitsSold OTHERWISE 1; }; //ARTIST AND MAECENAS RELATED GETTERS /* ** All the artist information */ $artistInfo = $artist=>var["artist_" || $artist]; $profile = $artist=>var["profile_" || $artist]; /* ** How many BYTES have maecenas invested in a given artist */ $totalArtistInvestment = $artist=>{ if (NOT is_valid_address($artist)) bounce("artist address is invalid"); $artistInf = $artistInfo($artist); if (typeof($artistInf) == "boolean") bounce("That artist does not accept maecenas"); return 11511570 * $artistInf.supply * (1 + $artistInf.supply) * (1 + 2 * $artistInf.supply); }; /* ** How many BYTES does the next share of the given artist costs */ $artistSharePrice = $artist=>{ $artistInf = var["artist_" || $artist]; if (typeof($artistInf) == "boolean") bounce("That artist does not accept investments"); return $_maecenasCurve($artistInf.supply); }; /* ** How many BYTES does it take to buy $shares amount of the given artist shares */ $artistSharesPrice = ($artist, $shares)=>{ if (NOT is_integer($shares)) bounce("shares must be an integer"); if ($shares <= 0) bounce("shares must be a positive integer"); if (NOT is_valid_address($artist)) bounce("artist address is invalid"); $artistInf = $artistInfo($artist); if (NOT $artistInf) bounce("that artist does not accept maecenas"); $x0 = $artistInf.supply; $x1 = $artistInf.supply + $shares; $upToFirstToken = 11511570 * $x0 * (1 + $x0) * (1 + 2 * $x0); $upToTargetPurchase = 11511570 * $x1 * (1 + $x1) * (1 + 2 * $x1); return round($upToTargetPurchase - ($upToFirstToken OTHERWISE 0), 0); }; /* ** How many SHARES of the given artist has the given maecenas */ $maecenasArtistShares = ($maecenas, $artist)=>{ if (NOT is_valid_address($artist)) bounce("artist address is invalid"); if (NOT is_valid_address($maecenas)) bounce("maecenas address is invalid"); return var["maecenas_" || $maecenas || "_" || $artist] OTHERWISE 0; }; /* ** How many BYTES have an investor accrued from the given artist */ $maecenasEarnings = ($maecenas, $artist)=>{ if (NOT is_valid_address($artist)) bounce("artist address is invalid"); if (NOT is_valid_address($maecenas)) bounce("maecenas address is invalid"); $artistInf = $artistInfo($artist); return floor($artistInf.share * $maecenasArtistShares($maecenas) / $artistInf.supply, 0); }; }", "messages": { "cases": [ { "if": "{ NOT $owner //The owner has not been set }", "messages": [ { "app": "state", "state": "{ var["owner"] = "IUU43O7TS2TBYKAPGKUARDZHOTAE275A"; //Set the Owner to my address var["locked"] = 0; //Bytes locked in bids are not withdrawable by the Owner }" } ] }, { "if": "{ trigger.address == $owner AND (trigger.data["method"] == "mint" OR trigger.data["method"] == "payout" OR trigger.data["method"] == "approve" OR trigger.data["method"] == "revoke" OR trigger.data["method"] == "transferOwnership" OR trigger.data["method"] == "verifyProfile") }", "messages": { "cases": [ { "if": "{ trigger.data["method"] == "mint" }", "init": "{ if (NOT exists(trigger.data["amount"])) bounce("amount field is mandatory"); if (NOT is_valid_amount(trigger.data["amount"])) bounce("The amount of NFT copies to mint is not valid"); if (NOT exists(trigger.data["ipfs"])) bounce("ipfs field is mandatory"); if (NOT exists(trigger.data["seller"])) bounce("seller field is mandatory"); if (NOT is_valid_address(trigger.data["seller"])) bounce("The seller address is not valid"); if (NOT exists(trigger.data["endTime"])) bounce("endTime field is mandatory"); if (NOT is_integer(trigger.data["endTime"])) bounce("endTime field is not a timestamp"); if (trigger.data["endTime"] <= timestamp) bounce("The endTime cannot be set in the past"); if (trigger.data["endTime"] - timestamp > 2628000) bounce("You cannot set the end time in more than 30 days in the future"); }", "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": "state", "state": "{ var["NFT_" || response_unit] = { bid: 20000, //Max current bid (a NFT can have this field because it was resold. Check for price field instead) by: trigger.data["seller"], at: timestamp, //Max bid time ipfs: trigger.data["ipfs"], //Hash of the content author: trigger.data["seller"], //The original seller soldAt: trigger.data["endTime"], //End of the auction soldBy: trigger.data["seller"] //Who is currently selling the NFT }; }" } ] }, { "init": "{ if (NOT exists(trigger.data["price"])) bounce("price field is mandatory if you intend to sell more than one NFT copy"); if (trigger.data["price"] < 20000) bounce("The minium price is 20000 bytes"); if (NOT is_valid_amount(trigger.data["price"])) bounce("price is not valid"); }", "messages": [ { "app": "asset", "payload": { "cap": "{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["NFT_" || response_unit] = { price: trigger.data["price"], //Sale price (this field is only present if the first sale was a fixed price one) at: timestamp, //Max bid time ipfs: trigger.data["ipfs"], //Hash of the content unitsSold: 0, author: trigger.data["seller"], //The original seller soldAt: trigger.data["endTime"], //End of the auction soldBy: trigger.data["seller"] //Who is currently selling the NFT }; }" } ] } ] } }, { "if": "{ trigger.data["method"] == "payout" }", "init": "{ //if ($spendableFunds <= 20000) // bounce("There are not enought funds to withdraw"); //DEBUG response["spendable"] = $spendableFunds; }", "messages": [ { "app": "payment", "payload": { "asset": "base", "outputs": [ { "address": "{trigger.address}" } ] } } ] }, { "if": "{ trigger.data["method"] == "approve" }", "init": "{ if (NOT exists(trigger.data["NFT"])) bounce("NFT field is mandatory"); $NFT = var["pending_" || trigger.data["NFT"]]; if (NOT $NFT) bounce("That NFT is not known by this AA"); }", "messages": [ { "app": "state", "state": "{ $isFreeNFT = var["free_" || trigger.data["NFT"]]; if ($isFreeNFT) var["free_" || trigger.data["NFT"]] = false; //Delete previous data so it is no longer tradable in the free market var["SOLD_" || trigger.data["NFT"]] = { author: "foreign", ipfs: $NFT.ipfs }; var["pending_" || trigger.data["NFT"]] = false; //Delete from the pendingApproval list }" } ] }, { "if": "{ trigger.data["method"] == "verifyProfile" }", "init": "{ if (NOT exists(trigger.data["artist"])) bounce("artist field is mandatory"); }", "messages": [ { "app": "state", "state": "{ var["profile_" || trigger.data["artist"]] ||= {verified: true}; }" } ] }, { "if": "{ trigger.data["method"] == "revoke" }", "init": "{ if (NOT exists(trigger.data["NFT"])) bounce("NFT field is mandatory"); }", "messages": [ { "app": "data_feed", "payload": { "{trigger.data["NFT"]}": "REVOKED" } } ] }, { "if": "{ trigger.data["method"] == "transferOwnership" }", "init": "{ if (NOT exists(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", "if": "{ $spendableFunds > 20000 }", "payload": { "asset": "base", "outputs": [ { "address": "{trigger.address}", "amount": "{$spendableFunds}" } ] } }, { "app": "state", "state": "{ var["owner"] = trigger.data["newOwner"];//Ownership is transferred }" } ] } ] } }, { "if": "{ trigger.data["method"] == "BUY" OR trigger.data["method"] == "DIVEST" OR trigger.data["method"] == "CLAIM" }", "init": "{ $NFT = exists(trigger.data["NFT"]) ? $saleInfo(trigger.data["NFT"]) : false; $artist = trigger.data["method"] == "DIVEST" ? $artistInfo(trigger.data["artist"]) : $artistInfo($NFT.author); if (trigger.data["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 (timestamp > $NFT.soldAt){ if ($isAuction){ if ($hasBidders) //You can still buy it if there were no bidders bounce("The auction is over"); } else{ bounce("The sale is already over"); } } } else if (trigger.data["method"] == "DIVEST"){ //Validate divest params if (NOT exists(trigger.data["artist"])) bounce("artist field is mandatory"); if (NOT is_valid_address(trigger.data["artist"])) bounce("artist's address is invalid"); if (NOT $artist) bounce("That artist never accepted maecenas"); if (NOT exists(trigger.data["amount"])) bounce("amount field is mandatory"); if (NOT is_integer(trigger.data["amount"]) OR trigger.data["amount"] <= 0) bounce("amount must be an integer > 0"); $investedAmount = var["maecenas_" || trigger.address || "_" || trigger.data["artist"]]; if (NOT $investedAmount) bounce("You have no shares of that artist"); if (trigger.data["amount"] > $investedAmount) bounce("You only have " || $investedAmount || " shares of that artist"); $yourShare = floor($artist.share * trigger.data["amount"] / $artist.supply, 0); if ($yourShare < 20000) bounce("It is not worth divesting your share"); } else if (trigger.data["method"] == "CLAIM"){ //Validate claim params if (NOT exists(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; /** DEBUG if (timestamp <= $NFT.soldAt) bounce("The auction is not over yet"); */ if ($NFT.bid == 0) 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 (trigger.data["method"] == "BUY") $maecenasShare = $artist.sharePercent * trigger.output[[asset="base"]].amount; else if (trigger.data["method"] == "CLAIM" AND $hasBidders) $maecenasShare = $artist.sharePercent * $NFT.bid; else $maecenasShare = 0; $sharesInThePool = (trigger.data["method"] != "DIVEST") ? $artist.supply : ($artist.supply - trigger.data["amount"]); //If divesting we need to substract divested shares if (trigger.data["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 (trigger.data["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 (trigger.data["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 response["maecenasShare"] = $maecenasShare; response["poolValue"] = $p; response["myPoolPercentage"] = $k; response["sharePrice"] = $price; response["shares"] = $shareIWillfinallyBuy; response["buyShares"] = $buyShares; response["takenFromPool"] = $myProfit; response["profit"] = $myProfit - $price*$shareIWillfinallyBuy; response["spendable"] = $totalSpendable; } 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) bounce("Your bid is lower or equal to the last bid. You must increase it"); if (trigger.output[[asset="base"]].amount <= $NFT.bid * (1 + $MIN_BID_INCREMENT)) bounce("Your bis 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.by = trigger.address; var["NFT_" || trigger.data["NFT"]] ||= $stripToken($extendDeadLine($NFT)); }" } ] }, { "init": "{ if ($NFT.unitsSold == $NFT.cap) bounce("All NFT copies have been already sold"); if (trigger.output[[asset="base"]].amount < $NFT.price) bounce("Your payment is lower than the NFT price. You have to send " || $NFT.price || " bytes"); }", "messages": [ { "app": "payment", "if": "{ floor($NFT.price * (1 - $HOUSE_CUT - ($allowsMaecenas ? (($hasMaecenas OR $buyShares) ? $artist.sharePercent : 0) : 0)) - 10000, 0) > 0 }", "payload": { "asset": "base", "outputs": [ { "address": "{$NFT.soldBy}", "amount": "{floor($NFT.price * (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 } ] } }, { "app": "state", "state": "{ var["NFT_" || trigger.data["NFT"]] ||= {unitsSold: $NFT.unitsSold + 1}; if ($hasMaecenas){ var["locked"] += $maecenasShare - $myProfit; var["artist_" || $NFT.author] ||= {share: $poolFinalValue}; } if ($NFT.unitsSold + 1 == $NFT.cap){ var["NFT_" || trigger.data["NFT"]] = false; //Delist it from sale var["SOLD_" || trigger.data["NFT"]] = $stripToken($NFT); //Add it to meta } }" } ] } ] } }, { "if": "{ trigger.data["method"] == "CLAIM" }", "messages": { "cases": [ { "if": "{//NFT was first sold $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 } ] } }, { "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 var["SOLD_" || trigger.data["NFT"]] = $stripToken($NFT); //Save for the next auction var["NFT_" || trigger.data["NFT"]] = false; //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 }", "payload": { "asset": "base", "outputs": { "cases": [ { "if": "{ floor($NFT.bid * $ARTIST_CUT, 0) - 10000 > 0 //It is worth paying the original artist }", "outputs": [ { "address": "{$NFT.soldBy}", "amount": "{floor($NFT.bid * (1 - $ARTIST_CUT) - 10000, 0)}" }, { "address": "{$NFT.author}", "amount": "{floor($NFT.bid * $ARTIST_CUT, 0) - 10000}" } ] }, { "outputs": [ { "address": "{$NFT.soldBy}", "amount": "{floor($NFT.bid * (1 - $ARTIST_CUT) - 10000, 0)}" } ] } ] } } }, { "app": "payment", "payload": { "asset": "{trigger.data['NFT']}", "outputs": [ { "address": "{$NFT.by}", "amount": 1 } ] } }, { "app": "state", "state": "{ var["locked"] -= $NFT.bid; var["SOLD_" || trigger.data["NFT"]] = $stripToken($NFT); //Save for the next auction var["NFT_" || trigger.data["NFT"]] = false; }" } ] } ] } }, { "if": "{ trigger.data["method"] == "DIVEST" }", "messages": [ { "app": "payment", "payload": { "asset": "base", "outputs": [ { "address": "{trigger.address}", "amount": "{$yourShare - 10000}" } ] } }, { "app": "state", "state": "{ var["artist_" || trigger.data["artist"]] ||= { share: $artist.share - $yourShare, //Decrease the share by the amount just divested supply: $artist.supply - trigger.data["amount"] //Decrease the supply by the shares used to divest }; var["maecenas_" || trigger.address || "_" || trigger.data["artist"]] -= trigger.data["amount"]; var["locked"] -= ($yourShare + $myProfit); }" } ] } ] } }, { "if": "{//[PUBLIC] Resell a NFT trigger.data["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"); $feedData = data_feed[[oracles=this_address, feed_name=trigger.output[[asset!="base"]].asset, ifnone=false, ifseveral="last", type="string"]]; $NFT = var["SOLD_" || trigger.output[[asset!="base"]].asset] || {isBanned: (typeof($feedData) == "string" AND $feedData == "REVOKED") ? true : false}; //[We need $NFT.isBanned]This already checks for $NFT existence if (NOT $NFT) bounce("NFT not found"); $sale = var["NFT_" || trigger.output[[asset!="base"]].asset]; if (trigger.output[[asset!="base"]].amount != 1) bounce("You cannot auction more than 1 copy of an NFT at a time"); if ($NFT.isBanned) bounce("We revoked the trading of that token probably due to copyright reasons"); if ($sale) bounce("A copy of that NFT is already being auctioned. The auction is expected to end at " || timestamp_to_string($sale.soldAt) || " UTC but may be delayed depending on the number of bids"); }", "messages": [ { "app": "state", "state": "{ $NFT.bid = trigger.data["initialPrice"]; $NFT.by = trigger.address; $NFT.soldBy = trigger.address; $NFT.at = timestamp; $NFT.soldAt = trigger.data["endTime"]; var["NFT_" || trigger.output[[asset!="base"]].asset] ||= $stripToken($NFT); }" } ] }, { "if": "{ trigger.data["method"] == "PRELIST" }", "init": "{ if (NOT exists(trigger.data["NFT"])) bounce("NFT field is mandatory"); if (NOT asset[trigger.data["NFT"]].exists) bounce("That NFT does not exist within the Obyte network"); if (NOT exists(trigger.data["ipfs"])) bounce("ipfs field is mandatory"); if (NOT is_valid_address(trigger.data["seller"])) bounce("The seller address is not valid"); if (NOT exists(trigger.data["duration"])) bounce("duration field is mandatory. Enter the auction duration in seconds"); if (NOT is_integer(trigger.data["duration"])) bounce("duration field is not a valid amount of seconds"); if (trigger.data["duration"] < 0) bounce("You cannot set a negative duration"); if (trigger.data["duration"] > 2628000) bounce("The auction cannot last more than 30 days"); }", "messages": [ { "app": "state", "state": "{ var["pending_" || trigger.data["NFT"]] = { ipfs: trigger.data["ipfs"] //Hash of the content }; }" } ] }, { "if": "{ trigger.data["method"] == "ENABLE_INVESTING" }", "init": "{ if (var["artist_" || trigger.address]) bounce("You are already accepting maecenas"); if (NOT exists(trigger.data["share"])) bounce("share field is mandatory"); if (NOT is_integer(trigger.data["share"]) OR trigger.data["share"] < 1 OR trigger.data["share"] > 50) bounce("share must be an integer between 1 - 50"); }", "messages": [ { "app": "state", "state": "{ var["artist_" || trigger.address] = { supply: 0, share: 0, sharePercent: trigger.data["share"] / 100 }; }" } ] }, { "if": "{ trigger.data["method"] == "INVEST" }", "init": "{ if (NOT exists(trigger.data["artist"])) bounce("artist field is mandatory"); if (NOT is_valid_address(trigger.data["artist"])) bounce("artist field is not a valid address"); if (NOT var["artist_" || trigger.data["artist"]]) bounce("That artist is not accepting maecenas"); if (NOT exists(trigger.data["amount"])) bounce("amount field is mandatory"); if (NOT is_integer(trigger.data["amount"]) OR trigger.data["amount"] <= 0) bounce("amount must be a positive integer"); $artist = $artistInfo(trigger.data["artist"]); $x0 = $artist.supply; $x1 = $artist.supply + trigger.data["amount"]; /* DEBUG $upToFirstToken = 11511570 * $x0 * (1 + $x0) * (1 + 2 * $x0); $upToTargetPurchase = 11511570 * $x1 * (1 + $x1) * (1 + 2 * $x1); */ $upToFirstToken = 10000/3 * $x0 * (1 + $x0) * (1 + 2 * $x0); $upToTargetPurchase = 10000/3 * $x1 * (1 + $x1) * (1 + 2 * $x1); $totalCost = round($upToTargetPurchase - $upToFirstToken, 0); if (trigger.output[[asset="base"]].amount < $totalCost) bounce("Your payment is not enough for that purchase. You need to send " || $totalCost || " bytes" || (trigger.data["amount"]>1 ? " or reduce the amount of maecenas tokens you are buying" : "")); }", "messages": [ { "app": "payment", "payload": { "asset": "base", "outputs": [ { "address": "{trigger.data["artist"]}", "amount": "{floor($totalCost * (1 - $INVESTMENT_CUT) - 10000, 0)}" } ] } }, { "app": "state", "state": "{ var["artist_" || trigger.data["artist"]] ||= {supply: $artist.supply + trigger.data["amount"]}; if (var["maecenas_" || trigger.address || "_" || trigger.data["artist"]]) var["maecenas_" || trigger.address || "_" || trigger.data["artist"]] += trigger.data["amount"]; else var["maecenas_" || trigger.address || "_" || trigger.data["artist"]] = trigger.data["amount"]; }" } ] }, { "if": "{ trigger.data["method"] == "PROFILE" }", "init": "{ $prof = $profile(trigger.address); if ($prof.verified) bounce("You have to contact support to modify a verified profile. We do this to prevent already verified accounts from impersonating another artist"); $profileObj = $prof || trigger.data || {verified: false}; delete($profileObj, "method"); }", "messages": [ { "app": "state", "state": "{ var["profile_" || trigger.address] = $profileObj; }" } ] }, { "if": "{ trigger.data["method"] == "SET_META" }", "init": "{ if (NOT exists(trigger.data["NFT"])) bounce("NFT field is mandatory"); $NFT = var["SOLD_" || trigger.data["NFT"]]; if (NOT $NFT) bounce("NFT not found"); if ($NFT.author != trigger.address) bounce("You can only set the metadata of NFTs minted by yourself"); }", "messages": [ { "app": "state", "state": "{ var["meta_" || trigger.data["NFT"]] = trigger.data; }" } ] }, { "if": "{ trigger.data["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 exists(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 ($NFT.bid) bounce("You cannot change an auction price!"); }", "messages": [ { "app": "state", "state": "{ var["NFT_" || trigger.data["NFT"]] ||= {price: trigger.data["price"]}; }" } ] }, { "if": "{ trigger.data["method"] == "FREELIST" }", "init": "{ if (trigger.output[[asset!="base"]].asset == "ambigous") bounce("You cannot send more than 1 NFT type per transaction"); if (trigger.output[[asset!="base"]].amount != 1) bounce("You cannot sell more than 1 NFT unit at a time"); $NFT = var["NFT_" || trigger.output[[asset!="base"]].asset] OTHERWISE var["SOLD_" || trigger.output[[asset!="base"]].asset]; if ($NFT) bounce("That NFT is already verified, thus it cannot be traded in the free market"); if(NOT exists(trigger.data["ipfs"])) bounce("ipfs field is required"); if (NOT exists(trigger.data["endTime"])) bounce("endTime field is mandatory"); if (NOT is_integer(trigger.data["endTime"])) bounce("endTime must be integer"); if (trigger.data["endTime"] < timestamp) bounce("endTime cannot be set in the past"); if (trigger.data["endTime"] > timestamp + 2628000) bounce("endTime cannot be set in more than a month in the future"); if (exists(trigger.data["price"])){ //Is normal sale if (NOT is_valid_amount(trigger.data["price"])) bounce("price is invalid"); else $toCreate = {price: trigger.data["price"]}; } else{ //Is auction $toCreate = {bid: 20000, by: trigger.address, at: timestamp}; } }", "messages": [ { "app": "state", "state": "{ var["FREE_" || trigger.output[[asset!="base"]].asset] = $toCreate || {ipfs: trigger.data["ipfs"], author: 'foreign', soldBy: trigger.address, soldAt: trigger.data["endTime"]}; }" } ] }, { "if": "{ trigger.data["method"] == "FREEBUY" }", "init": "{ if (NOT trigger.data["NFT"]) bounce("NFT field is mandatory"); if (NOT exists(trigger.data["NFT"])) bounce("NFT field is mandatory"); $NFT = var["FREE_" || trigger.data["NFT"]]; if (NOT $NFT) bounce("That NFT does not exist"); if (trigger.address == $NFT.soldBy) bounce("You cannot buy/bid on your own NFTs"); $isAuction = $NFT.bid ? true : false; if ($isAuction) if (trigger.output[[asset="base"]].amount < $NFT.bid * (1 + $MIN_BID_INCREMENT)) bounce("You have to send at least " || $NFT.bid * (1 + $MIN_BID_INCREMENT) || " bytes as you need to increment the current bet by at least 0.01%"); }", "messages": { "cases": [ { "if": "{ $isAuction }", "messages": [ { "app": "state", "state": "{ var["FREE_" || trigger.data["NFT"]] ||= {bid: trigger.output[[asset="base"]].amount, at: timestamp, by: trigger.address}; var["locked"] += trigger.output[[asset="base"]].amount; }" } ] }, { "messages": [ { "app": "payment", "payload": { "asset": "base", "outputs": [ { "address": "{trigger.address}", "amount": "{$NFT.price * (1 - $FREEMARKET_CUT)}" } ] } }, { "app": "payment", "payload": { "asset": "{trigger.data["NFT"]}", "outputs": [ { "address": "{trigger.address}", "amount": 1 } ] } } ] } ] } }, { "if": "{ trigger.data["method"] == "FREE_CLAIM" }", "init": "{ if (NOT trigger.data["NFT"]) bounce("NFT field is mandatory"); $NFT = var["FREE_" || trigger.data["NFT"]]; if (NOT $NFT) bounce("NFT not found"); if ($NFT.soldAt < timestamp) bounce("The auction/sale is not over yet"); $isAuction = $NFT.bid ? true : false; }", "messages": [ { "if": "{ $NFT.by != $NFT.soldBy }", "app": "payment", "payload": { "asset": "base", "outputs": [ { "address": "{$NFT.soldBy}", "amount": "{$NFT.price * (1 - $FREEMARKET_CUT)}" } ] } }, { "app": "payment", "payload": { "asset": "{trigger.data["NFT"]}", "outputs": [ { "address": "{$NFT.by}", "amount": 1 } ] } }, { "app": "state", "state": "{ var["FREE_" || trigger.data["NFT"]] = false; }" } ] } ] } } ]
Technical information
Fees:
35,230 bytes
(452 headers, 34778 payload)
Level:1950416
Witnessed level:1950408
Main chain index:1942451
Latest included mc index:1942450
Status:stable/confirmed/final