[
    "autonomous agent",
    {
        "init": "{
        $asset_ct = 'hd936lRtPN11pkgNv8qVnqN2OHMyAp8P/NsLp6KsuqA=';
        if(!var['-Last price'] and !trigger.data.price){
            bounce('Price must be defined before first exchange');
        }
        if(trigger.data.price){
            //bytes per 1 asset
            $ratio = round(trigger.data.price);
            if($ratio <= 0){
                bounce('Price not allowed');
            }
        }
        else{
            $ratio = var['-Last price'];
        }
        $addr = trigger.address;
        $base_inp = trigger.output[[asset=base]] - 700;
        if(trigger.output[[asset!=base]].asset != 'none')
            $asset = trigger.output[[asset!=base]].asset;
        if($asset){
            if($asset == 'ambiguous')
                bounce('Only 1 asset per tx');
            if($asset != $asset_ct)
                bounce('Asset not allowed, please send ' || $asset_ct);
            $asset_inp = (trigger.output[[asset!=base]] != 0) ? trigger.output[[asset!=base]] : bounce('Zero asset tx');
        }
        //user amounts-price
        $base_key =  $addr || $ratio || 'b';
        $asset_key = $addr || $ratio;
        //total amounts-price
        $total_key = 'b' || $ratio;
        $total_asset_key = 'a' || $ratio;
        //exchanged amounts, allow users to withdraw afterwards
        $exch_key = 'b_' || $ratio ;
        $exch_asset_key = 'a_' || $ratio ;
        //exchanged amounts are 'protected' until owners withdraw
        $max_b_to_exchange = var[$total_key] - var[$exch_key];
        $max_a_to_exchange = var[$total_asset_key] - var[$exch_asset_key];
        //base_inp without leftover bytes
        $base_inp_round = ($base_inp - ($base_inp % $ratio));
        $base_inp_in_asset = $base_inp_round/$ratio;
        $asset_inp_in_bytes = $asset_inp*$ratio;
        //allowed if there is exchanged amount and user deposited previously
        $withdraw_asset = var[$exch_asset_key] and var[$base_key] and var[$exch_asset_key] > 0 and var[$base_key] > 0;
        $withdraw_base = var[$exch_key] and var[$asset_key] and var[$exch_key] > 0 and var[$asset_key] > 0;
        //allowed if there is amount to exchange and user did not deposit previously for this price
        $exchange_asset = $asset and $byte_amount and !var[$base_key];
        $exchange_base = !$asset and $asset_amount and !var[$asset_key];
        //allowed if user has non-filled or partial filled orders to cancel
        $cancel_asset = trigger.data.cancel and var[$asset_key] and var[$asset_key] > 0;
        $cancel_base = trigger.data.cancel and var[$base_key] and var[$base_key] > 0;
    }",
        "messages": {
            "cases": [
                {
                    "if": "{
                        $withdraw_asset or $withdraw_base 
                    }",
                    "init": "{
                        $withdraw_key = $withdraw_asset ? $exch_asset_key : $exch_key;
                        $w_total_key = $withdraw_asset ? $total_asset_key : $total_key;
                        $max_to_withdraw = $withdraw_asset ? (var[$base_key] / $ratio) : (var[$asset_key] * $ratio);
                        $key = $withdraw_asset ? $base_key : $asset_key;
                        //user can withdraw all their exchanged amount or a part of their exchanged amount (rest of order could be cancel)
                        $withdraw_amount = (var[$withdraw_key] <= $max_to_withdraw) ? var[$withdraw_key] : $max_to_withdraw;
                    }",
                    "messages": [
                        {
                            "app": "payment",
                            "payload": {
                                "asset": "base",
                                "outputs": [
                                    {
                                        "address": "{$addr}",
                                        "amount": "{ $withdraw_asset ? $base_inp : ($withdraw_amount + $base_inp) }"
                                    }
                                ]
                            }
                        },
                        {
                            "if": "{$withdraw_asset}",
                            "app": "payment",
                            "payload": {
                                "asset": "{$asset_ct}",
                                "outputs": [
                                    {
                                        "address": "{$addr}",
                                        "amount": "{$withdraw_amount}"
                                    }
                                ]
                            }
                        },
                        {
                            "app": "state",
                            "state": "{
                            //substract withdrawn amount
                            var[$w_total_key] -= $withdraw_amount;
                            if(var[$w_total_key] == 0)var[$w_total_key] = false;
                            //substract exchanged amount
                            var[$withdraw_key] -= $withdraw_amount;
                            if(var[$withdraw_key] == 0)var[$withdraw_key] = false;
                            //substract user deposit
                            var[$key] -= $retire_asset ? ($withdraw_amount * $ratio) : ($withdraw_amount / $ratio);
                            if(var[$key] == 0)var[$key] = false;
                            response['message'] = 'withdrawn exchanged amount ('||$retire_asset ? 'assets': 'bytes' ||') at '||$ratio||' bytes per token';
                        }"
                        }
                    ]
                },
                {
                    "if": "{
                        if($asset){
                            //user sent assets
                            if($max_b_to_exchange and $max_b_to_exchange > 0 and !trigger.data.cancel){
                                //there are bytes to exchange
                                if($asset_inp_in_bytes > $max_b_to_exchange){
                                    //user sent more amount than allowed, exchange to max allowed
                                    $byte_amount = $max_b_to_exchange;
                                    //leftover
                                    $asset_amount = (($asset_inp_in_bytes - $max_b_to_exchange) - (($asset_inp_in_bytes - $max_b_to_exchange) % $ratio)) / $ratio;
                                }
                                else{
                                    //user sent less or equal amount than allowed, exchange to user input
                                    $byte_amount = $asset_inp_in_bytes;
                                    $asset_amount = 0;
                                }
                            }
                            else{
                                //there are no bytes to exchange, deposit allowed unless order cancelation
                                if(!trigger.data.cancel)
                                    $deposit = true;
                            }
                        }
                        else{
                            //user sent bytes
                            if($max_a_to_exchange and $max_a_to_exchange > 0 and !trigger.data.cancel){
                                //there are assets to exchange
                                if($base_inp_in_asset > $max_a_to_exchange){
                                    //user sent more amount than allowed, exchange to max allowed
                                    $asset_amount = $max_a_to_exchange;
                                    //leftover
                                    $byte_amount = ($base_inp_in_asset - $max_a_to_exchange) * $ratio;
                                }
                                else{
                                    //user sent less or equal amount than allowed, exchange to user input
                                    //fail fast to let user know
                                    if($base_inp_in_asset == 0)
                                        bounce('Not enough funds for minimum');
                                    $asset_amount =  $base_inp_in_asset;
                                    $byte_amount = 0;
                                }
                            }
                            else{
                                //there are no assets to exchange, deposit allowed unless order cancelation
                                if(!trigger.data.cancel)
                                    $deposit = true;
                            }
                        }
                        $exchange_asset or $exchange_base
                    }",
                    "messages": [
                        {
                            "if": "{$exchange_asset or $byte_amount > 0}",
                            "app": "payment",
                            "payload": {
                                "asset": "base",
                                "outputs": [
                                    {
                                        "address": "{$addr}",
                                        "amount": "{$exchange_asset ? ($byte_amount + $base_inp) : $byte_amount}"
                                    }
                                ]
                            }
                        },
                        {
                            "if": "{$exchange_base or $asset_amount > 0}",
                            "app": "payment",
                            "payload": {
                                "asset": "{$asset_ct}",
                                "outputs": [
                                    {
                                        "address": "{$addr}",
                                        "amount": "{$asset_amount}"
                                    }
                                ]
                            }
                        },
                        {
                            "app": "state",
                            "state": "{
                            var['-Last price'] = $ratio;
                            if($exchange_asset){
                                //sum exchanged amount
                                var[$total_asset_key] += $asset_inp - $asset_amount;
                                var[$exch_asset_key] +=  $asset_inp - $asset_amount;
                                
                                //substract taken amount
                                var[$total_key] -= $byte_amount;if(var[$total_key] == 0)var[$total_key] = false;
                                response['message'] = 'sold '||($asset_inp - $asset_amount)||' assets for '||($byte_amount)||' bytes';
                            }
                            else{
                                //sum exchanged amount
                                var[$total_key] += $base_inp_round - $byte_amount;
                                var[$exch_key] += $base_inp_round - $byte_amount;
                                //substract taken amount
                                var[$total_asset_key] -= $asset_amount;if(var[$total_asset_key] == 0)var[$total_asset_key] = false;
                                response['message'] = 'bought '||($asset_amount)||' assets for '||($base_inp_round - $byte_amount)||' bytes';
                            }
                        }"
                        }
                    ]
                },
                {
                    "if": "{    //if we are here, means user does not fulfill conditions to withdraw
                        $cancel_asset or $cancel_base
                    }",
                    "init": "{
                        $max_to_cancel = $cancel_asset ? $max_a_to_exchange : $max_b_to_exchange;
                        $key = $cancel_asset ? $asset_key : $base_key;
                        $cancel_tot_key = $cancel_asset ? $total_asset_key : $total_key;
                        //just in case
                        if($max_to_cancel <= 0){
                            bounce('Not allowed');
                        }
                        //cancel all amount if possible
                        $cancel_amount = ($max_to_cancel <= var[$key]) ? $max_to_cancel : var[$key];
                    }",
                    "messages": [
                        {
                            "app": "payment",
                            "payload": {
                                "asset": "base",
                                "outputs": [
                                    {
                                        "address": "{$addr}",
                                        "amount": "{$cancel_asset ? $base_inp : ($cancel_amount + $base_inp)}"
                                    }
                                ]
                            }
                        },
                        {
                            "if": "{$cancel_asset}",
                            "app": "payment",
                            "payload": {
                                "asset": "{$asset_ct}",
                                "outputs": [
                                    {
                                        "address": "{$addr}",
                                        "amount": "{$cancel_amount}"
                                    }
                                ]
                            }
                        },
                        {
                            "app": "state",
                            "state": "{
                            var[$cancel_tot_key] -= $cancel_amount;
                            if(var[$cancel_tot_key] == 0)var[$cancel_tot_key] = false;
                            var[$key] -= $cancel_amount;
                            if(var[$key] == 0)var[$key] = false;
                            response['message'] = 'canceled order ('||$cancel_asset?'sell':'buy'||' at '||$ratio||' bytes per token)';
                        }"
                        }
                    ]
                },
                {
                    "if": "{
                        $deposit otherwise bounce('Deposit not allowed, please cancel order first')
                    }",
                    "messages": [
                        {
                            "if": "{$asset}",
                            "app": "payment",
                            "payload": {
                                "asset": "base",
                                "outputs": [
                                    {
                                        "address": "{$addr}",
                                        "amount": "{$base_inp}"
                                    }
                                ]
                            }
                        },
                        {
                            "app": "state",
                            "state": "{
                            if($asset){
                                var[$total_asset_key] += $asset_inp;
                                var[$asset_key] += $asset_inp;
                                response['message'] = 'deposited '||$asset_inp||' assets to sell at '||$ratio||' bytes per token';
                            }
                            else{
                                var[$total_key] += $base_inp_round;
                                var[$base_key] += $base_inp_round;
                                response['message'] = 'deposited '||$base_inp_round||' bytes to buy at '||$ratio||' bytes per token';
                            }
                        }"
                        }
                    ]
                }
            ]
        }
    }
]