Definition: [
    "autonomous agent",
    {
        "bounce_fees": {
            "base": 10000
        },
        "init": "{
        $HOUSE_CUT = 0.03;    //We charge a 3% fee on all sales
        $BYTES_IN_GBYTE = 1000000000;
        if (NOT trigger.data["method"])
            bounce("method field is mandatory");
            
        $method = trigger.data["method"];
        $spendableFunds = balance["base"] - storage_size;   //The max amount I can withdraw without bouncing
        $owner = var["owner"];
        $oracle = var["oracle"];    //Used for GBYTE_USD price
    }",
        "messages": {
            "cases": [
                {
                    "if": "{
                    NOT $owner //The owner has not been set
                }",
                    "messages": [
                        {
                            "app": "state",
                            "state": "{
                            var["owner"] = "IUU43O7TS2TBYKAPGKUARDZHOTAE275A";
                            var["oracle"] = "F4KHJUCLJKY4JV7M5F754LAJX4EB7M4N";
                        }"
                        }
                    ]
                },
                {
                    "if": "{
                    trigger.address == $owner
                    AND ($method == "payout"    //We also check the method so the Owner can also act as an user
                    OR $method == "mint"
                    OR $method == "stopSale"
                    OR $method == "transferOwnership"
                    OR $method == "setOracle")
                }",
                    "messages": {
                        "cases": [
                            {
                                "if": "{
                                $method == "payout"
                            }",
                                "messages": [
                                    {
                                        "app": "payment",
                                        "payload": {
                                            "asset": "base",
                                            "outputs": [
                                                {
                                                    "address": "{trigger.address}",
                                                    "amount": "{$spendableFunds}"
                                                }
                                            ]
                                        }
                                    }
                                ]
                            },
                            {
                                "if": "{
                                $method == "transferOwnership"
                            }",
                                "init": "{
                                if (NOT trigger.data["newOwner"])
                                    bounce("newOwner field is mandatory");
                                if (NOT is_valid_address(trigger.data["newOwner"]))
                                    bounce("newOwner field is not a valid address");
                            }",
                                "messages": [
                                    {
                                        "app": "payment",
                                        "payload": {
                                            "asset": "base",
                                            "outputs": [
                                                {
                                                    "address": "{trigger.address}",
                                                    "amount": "{$spendableFunds}"
                                                }
                                            ]
                                        }
                                    },
                                    {
                                        "app": "state",
                                        "state": "{
                                        var["owner"] = trigger.data["newOwner"];
                                    }"
                                    }
                                ]
                            },
                            {
                                "if": "{
                                $method == "mint"
                            }",
                                "init": "{
                                if (NOT exists(trigger.data["amount"]))
                                    bounce("amount field is mandatory. Set it to 0 for unlimited");
                                if ((NOT is_valid_amount(trigger.data["amount"])) AND trigger.data["amount"] != 0)  //amount=0 => uncapped
                                    bounce("The amount of NFT copies to mint is not valid");
                                $price = trigger.data["priceUSD"] OTHERWISE trigger.data["price"];
                                if (NOT $price)
                                    bounce("price or priceUSD field must be filled");
                                if (NOT trigger.data["title"])
                                    bounce("title field is mandatory");
                                if (NOT trigger.data["priceUSD"]){  //It is priced in bytes
                                    if ($price < 20000)
                                        bounce("The minium price is 20000 bytes");
                                    if (NOT is_valid_amount($price))
                                        bounce("price is not valid");
                                }
                            
                                if (NOT trigger.data["ipfs"])   //meta.json
                                    bounce("ipfs field is mandatory");
                                if (exists(trigger.data["validity"])){
                                    if (NOT is_integer(trigger.data["validity"]))
                                        bounce("validity must be an integer");
                                    if (trigger.data["validity"] <= 0)
                                        bounce("You cannot make a license valid for 0s");
                                }
                                if (NOT is_valid_address(trigger.data["seller"]))
                                    bounce("The seller address is not valid");
                                $pendingNaming = var["NFT_" || var["pendingNaming"]];    //Previosly issued NFT
                            }",
                                "messages": {
                                    "cases": [
                                        {
                                            "if": "{
                                            trigger.data["amount"]
                                        }",
                                            "messages": [
                                                {
                                                    "app": "asset",
                                                    "payload": {
                                                        "cap": "{trigger.data["amount"]}",
                                                        "is_private": false,
                                                        "is_transferrable": "{trigger.data["tranferrable"]}",
                                                        "auto_destroy": false,
                                                        "fixed_denominations": false,
                                                        "issued_by_definer_only": true,
                                                        "cosigned_by_definer": false,
                                                        "spender_attested": false
                                                    }
                                                },
                                                {
                                                    "app": "data",
                                                    "if": "{
                                                    $pendingNaming
                                                }",
                                                    "payload": {
                                                        "asset": "{var["recordToData"]}",
                                                        "name": "{$pendingNaming.title || "license"}",
                                                        "author": "{$pendingNaming.seller}",
                                                        "ipfs": "{$pendingNaming.ipfs}",
                                                        "type": "LIC",
                                                        "decimals": 0
                                                    }
                                                },
                                                {
                                                    "app": "state",
                                                    "state": "{
                                                    var["NFT_" || response_unit] = {
                                                        price: trigger.data["price"] OTHERWISE false,
                                                        priceUSD: trigger.data["priceUSD"] OTHERWISE false,
                                                        title: trigger.data["title"],
                                                        ipfs: trigger.data["ipfs"],
                                                        author: trigger.data["seller"],
                                                        validity: trigger.data["validity"],
                                                        onSale: true
                                                    };
                                                    var["pendingNaming"] = response_unit;
                                                }"
                                                }
                                            ]
                                        },
                                        {
                                            "messages": [
                                                {
                                                    "app": "asset",
                                                    "payload": {
                                                        "is_private": false,
                                                        "is_transferrable": "{trigger.data["tranferrable"] OTHERWISE false}",
                                                        "auto_destroy": false,
                                                        "fixed_denominations": false,
                                                        "issued_by_definer_only": true,
                                                        "cosigned_by_definer": false,
                                                        "spender_attested": false
                                                    }
                                                },
                                                {
                                                    "app": "data",
                                                    "if": "{
                                                    $pendingNaming
                                                }",
                                                    "payload": {
                                                        "asset": "{var["recordToData"]}",
                                                        "name": "{$pendingNaming.title OTHERWISE "Untitled"}",
                                                        "author": "{$pendingNaming.seller}",
                                                        "ipfs": "{$pendingNaming.ipfs}",
                                                        "type": "LIC",
                                                        "decimals": 0
                                                    }
                                                },
                                                {
                                                    "app": "state",
                                                    "state": "{
                                                    var["NFT_" || response_unit] = {
                                                        price: trigger.data["price"] OTHERWISE false,
                                                        priceUSD: trigger.data["priceUSD"] OTHERWISE false,
                                                        title: trigger.data["title"],
                                                        ipfs: trigger.data["ipfs"],                                    //Hash of the content
                                                        author: trigger.data["seller"],                                //The original seller
                                                        onSale: true
                                                    };
                                                    var["recordToData"] = response_unit;
                                                }"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            },
                            {
                                "if": "{
                                $method == "setOracle"
                            }",
                                "init": "{
                                if (NOT is_valid_address(trigger.data["oracle"]))
                                    bounce("Invalid oracle address");
                                if (NOT data_feed[[oracles=trigger.data["oracle"], feed_name="GBYTE_USD", ifseveral="last"]])
                                    bounce("That oracle is not posting a GBYTE_USD datafeed");
                            }",
                                "messages": [
                                    {
                                        "app": "state",
                                        "state": "{
                                        var["oracle"] = trigger.data["oracle"];
                                    }"
                                    }
                                ]
                            }
                        ]
                    }
                },
                {
                    "if": "{
                    $method == "END_SALE"
                }",
                    "init": "{
                    if (NOT trigger.data["NFT"])
                        bounce("NFT field is mandatory");
                    $NFT = var["NFT_" || trigger.data["NFT"]];
                    if (NOT $NFT)
                        bounce("That NFT is not known by this AA");
                    if (trigger.address != $NFT.author AND trigger.address != $owner)   //The owner can also stops sales (as we expect authors losing their private keys)
                        bounce("You cannot stop a sale not created by yourself");
                }",
                    "messages": [
                        {
                            "app": "state",
                            "state": "{
                            var["NFT_" || trigger.data["NFT"]] ||= {onSale: false};
                        }"
                        }
                    ]
                },
                {
                    "if": "{
                    trigger.data["method"] == "BUY"
                }",
                    "init": "{
                    $NFT = var["NFT_" || trigger.data["NFT"]];
                    if (NOT $NFT.onSale)
                        bounce("That NFT is not on sale");
                    $expectedAmount = $NFT.price
                        ? $NFT.price
                        : round($NFT.priceUSD * 1 / data_feed[[oracles=$oracle, feed_name="GBYTE_USD", ifseveral="last"]] * $BYTES_IN_GBYTE, 0);
                    if (trigger.output[[asset="base"]].amount < $expectedAmount)
                        bounce("Your payment is lower than the NFT price. You have to send " || $expectedAmount || " bytes");
                    $pendingNaming = var["NFT_" || var["recordToData"]];
                }",
                    "messages": [
                        {
                            "app": "payment",
                            "if": "{
                            floor($expectedAmount * (1 - $HOUSE_CUT), 0) > 0
                        }",
                            "payload": {
                                "asset": "base",
                                "outputs": [
                                    {
                                        "address": "{$NFT.author}",
                                        "amount": "{floor($expectedAmount * (1 - $HOUSE_CUT), 0)}"
                                    }
                                ]
                            }
                        },
                        {
                            "app": "payment",
                            "payload": {
                                "asset": "{trigger.data['NFT']}",
                                "outputs": [
                                    {
                                        "address": "{trigger.address}",
                                        "amount": 1
                                    }
                                ]
                            }
                        },
                        {
                            "app": "data",
                            "if": "{
                            $pendingNaming
                        }",
                            "payload": {
                                "asset": "{var["recordToData"]}",
                                "name": "{$pendingNaming.title OTHERWISE "Untitled"}",
                                "author": "{$pendingNaming.seller}",
                                "ipfs": "{$pendingNaming.ipfs}",
                                "type": "LIC",
                                "decimals": 0
                            }
                        },
                        {
                            "app": "state",
                            "state": "{
                            if ($pendingNaming){
                                var["recordToData"] = false;
                            }
                            if ($NFT.validity){
                                var[trigger.data["NFT"] || trigger.data["address"]] = timestamp + $NFT.validity;
                            }
                        }"
                        }
                    ]
                },
                {
                    "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 ($NFT.author != trigger.address)
                        bounce("You can only change the price of your own licenses!");
                    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");
                }",
                    "messages": [
                        {
                            "app": "state",
                            "state": "{
                            var["NFT_" || trigger.data["NFT"]] ||= {
                                price: $NFT.price ? trigger.data["price"] : false,
                                priceUSD: $NFT.priceUSD ? trigger.data["price"] : false
                            };
                        }"
                        }
                    ]
                },
                {
                    "if": "{
                    $method == "REDEEM"
                }",
                    "init": "{
                    if (NOT exists(trigger.data["spack"]))
                        bounce("You need to provide a signed package");
                    $spack = json_parse(trigger.data["spack"]);
                    if (NOT is_valid_signed_package($spack, $spack.authors[0].address))
                        bounce("The signed message signature is invalid");
                    if (NOT $spack.signed_message.NFT)
                        bounce("The signer of this message did not include a NFT field");
                    $NFT = var["NFT_" || $spack.signed_message.NFT];
                    
                    //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 ($spack.signed_message.expireDate){
                        if ($spack.signed_message.expireDate < timestamp)
                            bounce("That license is no longer claimable");
                    }
                    $signedAmount = $spack.signed_message.amount OTHERWISE 1;
                    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 units were issued
                    if ($amount == 0)
                        bounce("All units 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};
                        }"
                        }
                    ]
                }
            ]
        }
    }
]