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;
        $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
            };
        };
        /*
        ** All the artist information
        */
        $artistInfo = $artist=>var["artist_" || $artist];
        $profile = $artist=>var["profile_" || $artist];
        /*
        ** 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 is also recommended.
            */
            $info = var["FREE_" || $NFT] OTHERWISE var["NFT_" || $NFT];
            $transferrable = $unit.messages[[.app="asset"]].payload.transferrable;
            if (NOT $transferrable)//Do not return info about non transferrable NFTs as they cannot get listed in other platforms
                return false;
            return $info || {
                cap: $unit.messages[[.app="asset"]].payload.cap,
                mintedAt: $unit.timestamp
            };
        };
    }",
        "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"
                    OR $method == "verifyProfile")
                }",
                    "messages": {
                        "cases": [
                            {
                                "if": "{
                                $method == "payout"
                            }",
                                "messages": [
                                    {
                                        "app": "payment",
                                        "payload": {
                                            "asset": "base",
                                            "outputs": [
                                                {
                                                    "address": "{trigger.address}",
                                                    "amount": "{$spendableFunds}"
                                                }
                                            ]
                                        }
                                    }
                                ]
                            },
                            {
                                "if": "{
                                $method == "verifyProfile"
                            }",
                                "init": "{
                                if (NOT trigger.data["artist"])
                                    bounce("artist field is mandatory");
                                $prof = var["profile_" || trigger.data["artist"]];
                            }",
                                "messages": [
                                    {
                                        "app": "attestation",
                                        "payload": "{
                                        {
                                            address: trigger.data["artist"],
                                            profile: $prof
                                        }
                                    }"
                                    },
                                    {
                                        "app": "state",
                                        "state": "{
                                        var["profile_" || trigger.data["artist"]] ||= {verified: true};
                                        var["user_" || $prof.username] = trigger.data["artist"]; //Username is now taken
                                    }"
                                    }
                                ]
                            },
                            {
                                "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.data["seller"] OTHERWISE 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");
                        $prof = var["profile_" || trigger.address];
                        $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 ($price < 20000)
                                        bounce("The minium price is 20000 bytes");
                                    if (NOT is_valid_amount($price))
                                        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["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
                                            };
                                        }"
                                    }
                                ]
                            }
                        ]
                    }
                },
                {
                    "if": "{
                        $method == "BUY"
                        OR $method == "DIVEST"
                        OR $method == "CLAIM"
                    }",
                    "init": "{
                        $NFT = exists(trigger.data["NFT"])
                            ? $saleInfo(trigger.data["NFT"])
                            : false;
                         $artist = $method == "DIVEST"
                            ? $artistInfo(trigger.data["artist"])
                            : $artistInfo($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 (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 ($method == "DIVEST"){    //Validate divest params
                            if (NOT 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 ($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 = $artist.sharePercent * trigger.output[[asset="base"]].amount;
                                else if ($method == "CLAIM" AND $hasBidders)
                                    $maecenasShare = $artist.sharePercent * $NFT.bid;
                                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");
                                                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": "{
                                                        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};
                                                        if ($hasMaecenas){
                                                            var["locked"] += $maecenasShare - $myProfit;
                                                            var["artist_" || $NFT.author] ||= {share: $poolFinalValue};
                                                        }
                                                        if ($NFT.unitsSold + 1 == $NFT.cap){
                                                            if (var["FREE_" || trigger.data["NFT"]])
                                                                var["FREE_" || trigger.data["NFT"]] ||= {bid: 0, price: false, soldAt: timestamp}; //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}; //Prepare for auction and delist it from normal sale
                                                        }
                                                    }"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            },
                            {
                                "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
                                                            }
                                                        ]
                                                    }
                                                },
                                                {
                                                    "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": "{
                                    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": "{
                    $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 = json_parse(trigger.data["signed_message"]) || json_parse(trigger.data["authors"]) || json_parse(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 does not include a NFT field");
                    $NFT = $saleInfo($spack.signed_message.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. Otherwise the NFT can be redeemed even if the sale was over.
                    if ($NFT.endTime < timestamp AND $spack.signed_message.expire)
                        bounce("That NFT is no longer claimable");
                    $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");
                    if ($NFT.author != $spack.authors[0].address)
                        bounce("The signer of that message is not the author of that NFT");
                    if (NOT $NFT)
                        bounce("That NFT does not exist");
                }",
                    "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};
                        }"
                        }
                    ]
                },
                {
                    "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");
                        $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)
                            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 == "PRELIST"
                    }",
                    "init": "{
                        if (NOT 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 trigger.data["ipfs"])
                            bounce("ipfs field is mandatory");
                        if (NOT trigger.data["type"])
                            bounce("type field is required");
                    }",
                    "messages": [
                        {
                            "app": "state",
                            "state": "{
                                var["pending_" || trigger.data["NFT"]] = {    //We save it as pending approval until we verify the provided info is valid
                                    ipfs: trigger.data["ipfs"],
                                    type: trigger.data["type"]
                                };
                            }"
                        }
                    ]
                },
                {
                    "if": "{
                        $method == "ENABLE_INVESTING"
                    }",
                    "init": "{
                        if (var["artist_" || trigger.address])
                            bounce("You are already accepting maecenas");
                        if (NOT 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");
                        if (exists(trigger.data["selfBuy"])){
                            if (NOT is_integer(trigger.data["selfBuy"]))
                                bounce("selfBuy field must be an integer");
                            if (trigger.data["selfBuy"] < 0)
                                bounce("selfBuy must be a positive integer");
                            $cost = (1161570 * trigger.data["selfBuy"] * (1 + trigger.data["selfBuy"]) * (1 + 2 * trigger.data["selfBuy"])) * $INVESTMENT_CUT;
                            if (trigger.output[[asset="base"]].amount < $cost)
                                bounce("You need to send at least " || $cost || " bytes");
                        }
                    }",
                    "messages": [
                        {
                            "app": "state",
                            "state": "{
                                var["artist_" || trigger.address] = {
                                    supply: trigger.data["selfBuy"] OTHERWISE 0,
                                    share: 0,
                                    sharePercent: trigger.data["share"] / 100
                                };
                                if (trigger.data["selfBuy"])
                                    var["maecenas_" || trigger.address || "_" || trigger.address] = trigger.data["selfBuy"];
                            }"
                        }
                    ]
                },
                {
                    "if": "{
                        $method == "DISABLE_INVESTING"
                    }",
                    "init": "{
                           $info = $artistInfo(trigger.address);
                           if (NOT $info)
                               bounce("You are already not accepting maecenas");
                           if ($info.supply > 0)
                               bounce("You cannot stop accepting maecenas right now as you already have some");
                       }",
                    "messages": [
                        {
                            "app": "state",
                            "state": "{
                                var["artist_" || trigger.address] = false;
                            }"
                        }
                    ]
                },
                {
                    "if": "{
                        $method == "INVEST"
                    }",
                    "init": "{
                        if (NOT trigger.data["artist"])
                            bounce("artist field is mandatory");
                        $artist = $artistInfo(trigger.data["artist"]);
                        if (NOT $artist)
                            bounce("That artist is not accepting maecenas");
                        if (NOT 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");
                        $x0 = $artist.supply;
                        $x1 = $artist.supply + trigger.data["amount"];
                        $upToFirstToken = 1161570 * $x0 * (1 + $x0) * (1 + 2 * $x0);
                        $upToTargetPurchase = 1161570 * $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");
                    }",
                    "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": "{
                        $method == "PROFILE"
                    }",
                    "init": "{
                        $prof = $profile(trigger.address);
                        $oldUsername = $prof.username;
                        $newUsername = trigger.data["username"] OTHERWISE $oldUsername;
                        if (NOT $oldUsername){
                             if (NOT trigger.data["username"])
                                bounce("username field is mandatory");
                        }
                        
                        if (var["user_" || $newUsername]){
                            if ($oldUsername){
                                if ($oldUsername != $newUsername){
                                    bounce("username already taken by a verified user");
                                }
                            }
                        }
                        if ($prof)
                            $profileObj = $prof || trigger.data || {username: $newUsername, verified: false};
                        else
                            $profileObj = trigger.data || {verified: false, username: $newUsername};
                        delete($profileObj, "method");
                    }",
                    "messages": [
                        {
                            "app": "state",
                            "state": "{
                                var["profile_" || trigger.address] = $profileObj;
                                if ($oldUsername){
                                    if ($oldUsername != $newUsername)
                                        var["user_" || $oldUsername] = false; //Free old username
                                }
                            }"
                        }
                    ]
                },
                {
                    "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 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"]};
                            }"
                        }
                    ]
                }
            ]
        }
    }
]