[
"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 exists(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 == "stopSale"
OR $method == "transferOwnership"
OR $method == "setOracle"
OR $method == "setHelper"
OR $method == "removeHelper")
}",
"messages": {
"cases": [
{
"if": "{
$method == "payout"
}",
"messages": [
{
"app": "payment",
"payload": {
"asset": "base",
"outputs": [
{
"address": "{trigger.address}",
"amount": "{$spendableFunds}"
}
]
}
}
]
},
{
"if": "{
$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",
"payload": {
"asset": "base",
"outputs": [
{
"address": "{trigger.address}",
"amount": "{$spendableFunds}"
}
]
}
},
{
"app": "state",
"state": "{
var["owner"] = trigger.data["newOwner"];
}"
}
]
},
{
"if": "{
$method == "setOracle"
}",
"init": "{
if (NOT exists(trigger.data["oracle"]))
bounce("oracle field is mandatory");
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 == "setHelper"
}",
"init": "{
if (NOT exists(trigger.data["helper"]))
bounce("helper field is mandatory");
if (NOT is_valid_address(trigger.data["helper"]))
bounce("helper address is invalid");
}",
"messages": [
{
"app": "state",
"state": "{
var["helper_" || trigger.data["helper"]] = true;
}"
}
]
},
{
"if": "{
$method == "removeHelper"
}",
"init": "{
if (NOT exists(trigger.data["helper"]))
bounce("helper field is mandatory");
if (NOT is_valid_address(trigger.data["helper"]))
bounce("helper address is invalid");
}",
"messages": [
{
"app": "state",
"state": "{
var["helper_" || trigger.data["helper"]] = false;
}"
}
]
}
]
}
},
{
"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"];
$isHelper = trigger.data["helper_" || trigger.address];
if (NOT $price OR $price < 0) //Check that priceUSD is > 0
bounce("price or priceUSD field must be filled and it must be a positive number");
if (NOT exists(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 (exists(trigger.data["maxPeriods"])){
if (NOT is_integer(trigger.data["maxPeriods"]))
bounce("maxPeriods must be an integer");
if (trigger.data["maxPeriods"] <= 0)
bounce("maxPeriods must be positive");
if (NOT exists(trigger.data["validity"]))
bounce("If you set maxPeriods you have to set validity too");
}
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 or less");
}
if (trigger.address == $owner OR $isHelper){ //These NFTs will be listed for sale so we need metadata about them
if (NOT exists(trigger.data["ipfs"])) //meta.json
bounce("ipfs field is mandatory");
if (NOT exists(trigger.data["title"]))
bounce("title field is mandatory");
if (trigger.address == $owner){ //Only the owner can set a third party as the seller to prevent approved sellers to troll another sellers by creating licensed on their name
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");
}
$pendingNaming = var["NFT_" || var["pendingNaming"]]; //Previosly issued NFT
}
if (exists(trigger.data["soldAt"])){
if (NOT is_integer(trigger.data["soldAt"]))
bounce("soldAt must be an integer");
if (trigger.data["soldAt"] <= timestamp)
bounce("soldAt cannot be set in the past");
}
$isTransferrable = exists(trigger.data["validity"]) //Timed licenses are NOT transferrable
? false
: trigger.data["transferrable"];
}",
"messages": {
"cases": [
{
"if": "{
trigger.data["amount"]
}",
"messages": [
{
"app": "asset",
"payload": {
"cap": "{trigger.data["amount"]}",
"is_private": false,
"is_transferrable": "{$isTransferrable}",
"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")|| " license"}",
"author": "{$pendingNaming.author}",
"ipfs": "{$pendingNaming.ipfs}",
"type": "LIC",
"decimals": 0
}
},
{
"app": "state",
"state": "{
if (trigger.address == $owner OR $isHelper){
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"] OTHERWISE false,
maxPeriods: trigger.data["maxPeriods"] OTHERWISE false,
soldAt: trigger.data["soldAt"] OTHERWISE false,
onSale: true
};
var["pendingNaming"] = response_unit;
}
else{
var["FREE_" || response_unit] = {
price: trigger.data["price"] OTHERWISE false,
priceUSD: trigger.data["priceUSD"] OTHERWISE false,
author: trigger.address,
validity: trigger.data["validity"],
maxPeriods: trigger.data["maxPeriods"],
soldAt: trigger.data["soldAt"] OTHERWISE false,
onSale: true
};
}
}"
}
]
},
{
"messages": [
{
"app": "asset",
"payload": {
"is_private": false,
"is_transferrable": "{$isTransferrable}",
"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")|| " license"}",
"author": "{$pendingNaming.author}",
"ipfs": "{$pendingNaming.ipfs}",
"type": "LIC",
"decimals": 0
}
},
{
"app": "state",
"state": "{
if (trigger.address == $owner OR $isHelper){
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"] OTHERWISE false,
maxPeriods: trigger.data["maxPeriods"] OTHERWISE false,
onSale: true
};
var["pendingNaming"] = response_unit;
}
else{
var["FREE_" || response_unit] = {
price: trigger.data["price"] OTHERWISE false,
priceUSD: trigger.data["priceUSD"] OTHERWISE false,
author: trigger.address,
validity: trigger.data["validity"],
maxPeriods: trigger.data["maxPeriods"],
onSale: true
};
}
}"
}
]
}
]
}
},
{
"if": "{
$method == "END_SALE"
}",
"init": "{
if (NOT exists(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) //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"]];
$previousExpiry = var[trigger.address || "_" || trigger.data["NFT"]] OTHERWISE timestamp;
if ($NFT.soldAt){
if ($NFT.soldAt < timestamp)
bounce("That license sale period ended on " || timestamp_to_string($NFT.soldAt) || " UTC");
}
if (NOT $NFT.onSale)
bounce("That license is not on sale");
if (exists(trigger.data["periods"])){
if (NOT is_integer(trigger.data["periods"]))
bounce("periods must be an integer");
if ($NFT.validity AND $NFT.maxPeriods){ //If it is a timed license with a maximum amount of periods check if the purchase does not exceed max purchasable time
if ($previousExpiry + trigger.data["periods"] * $NFT.validity > timestamp + ($NFT.maxPeriods OTHERWISE 1) * $NFT.validity)
bounce("You cannot buy that many periods in advance. You have to wait until your license is closer to expiry date");
}
}
$periods = trigger.data["periods"] OTHERWISE 1;
$expectedAmount = $periods * ($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") || " license"}",
"author": "{$pendingNaming.author}",
"ipfs": "{$pendingNaming.ipfs}",
"type": "LIC",
"decimals": 0
}
},
{
"app": "state",
"state": "{
if ($pendingNaming){
var["recordToData"] = false;
}
if ($NFT.validity){ //It is a timed license, lets save expiry date for the buyer
var[trigger.address || "_" || trigger.data["NFT"]] = $previousExpiry + $NFT.validity * $periods; //Add the just purchased time to the subscription
}
}"
}
]
},
{
"if": "{
$method == "CHANGE_PRICE"
}",
"init": "{
if (NOT exists(trigger.data["NFT"]))
bounce("NFT field is mandatory");
$NFT = var["NFT_" || trigger.data["NFT"]] OTHERWISE var["FREE_" || trigger.data["NFT"]];
$isRegisteredNFT = 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 (exists(trigger.data["price"])){
if (NOT is_integer(trigger.data["price"]))
bounce("price must be an integer");
if (NOT is_valid_amount(trigger.data["price"]) OR trigger.data["price"] < 20000)
bounce("price must be > 20.000 bytes");
if (exists(trigger.data["priceUSD"]))
bounce("You cannot set price and priceUSD at the same time");
}
if (NOT exists(trigger.data["price"]) AND NOT exists(trigger.data["priceUSD"]))
bounce("You have to provide either price or priceUSD field");
$price = trigger.data["price"] OTHERWISE trigger.data["priceUSD"];
}",
"messages": [
{
"app": "state",
"state": "{
if ($isRegisteredNFT){
var[($isRegisteredNFT ? "NFT_" : "FREE_") || trigger.data["NFT"]] ||= { //Dirty trick in key calculation to save complexity
price: exists(trigger.data["price"]) ? $price : false,
priceUSD: exists(trigger.data["priceUSD"]) ? $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];
if (NOT $NFT)
bounce("That license does not exist");
//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;
$unit = unit[$spack.signed_message.NFT];
$cap = $unit.messages[[.app="asset"]].payload.cap;
if ($NFT.author != $spack.authors[0].address)
bounce("The signer of that message is not the author of that license");
}",
"messages": [
{
"app": "payment",
"payload": {
"asset": "{$spack.signed_message.NFT}",
"outputs": [
{
"address": "{trigger.address}",
"amount": "{$NFT.signedAmount}"
}
]
}
},
{
"app": "state",
"state": "{
if ($NFT.validity){
var[trigger.address || "_" || $spack.signed_message.NFT] = (var[trigger.address || "_" || $spack.signed_message.NFT] OTHERWISE 0) + $NFT.signedAmount * $NFT.validity;
}
}"
}
]
}
]
}
}
]