[
    "autonomous agent",
    {
        "bounce_fees": {
            "base": 11000
        },
        "init": "{
        $aa_name = "CODAAA"; // Safe Autonomous Agent Forwarding Estate;
        $aa_asset_creation_and_issuing = "
O7NYCFUL5XIJTYE3O4MKGMGMTN6ATQAJ"; // could withdraw the dust is calculable;
        $DAY = 60 * 60 * 24;
        $WEEK = 7 * $DAY;
        $YEAR = 364.25 * $DAY;
        $TOTAL_CODS_AMOUNT=1e15;
        // BONUS RELATED STUFF
        $DEBUG = true;
        // There is a give away period for people ready to stake their bytes:
            $GIVEAWAY_PERIOD = $DEBUG ? 15*60 : 0.5 * $YEAR;
        // at the beginning of the give away period the bonus is max:
            $MAX_BONUS_P100 = 200;
        // then during every day the bonus is reducing:
            $DAILY_BONUS_REDUCTION_P100 = 1; 
        // We need better interest for longer stake:  return = 0.7 * ln(period) + 1.5
        // Viva robin the hood!, we need to steal the riches to feed the pool: reduction_p100 = 0.04 * ln(balance) - 0.31
        // ACCOUNTING RELATED STUFF
        // Every given time interest should be computed and paied by each user
            $ACCOUNTING_PERIOD = 1 * $YEAR;
        // from the pool of unclaim coins, we can allow a percentage per week
            $YEARLY_INTEREST_P100_FROM_POOL = 4 / 52; // 4% per year
        // load state concerning the CODAA
            $temp_next_accounting_time = var["next_accounting_time"] otherwise 0;
            $temp_interest_next_accounting = var["interest_next_accounting"] otherwise 0;
            $temp_pool_balance = var["pool_balance"] otherwise $TOTAL_CODS_AMOUNT;
        // load state concerning the user
            $account_name = trigger.data.account_name otherwise bounce ("Please specify an account name");
            $user_bytes = var[trigger.address||"_"||$account_name||"_bytes"] otherwise 0;
            $user_cods = var[trigger.address||"_"||$account_name||"_cods"] otherwise 0;
            $user_stake_start = var[trigger.address||"_"||$account_name||"_stake_start"] otherwise timestamp;
            $user_predicted_lock_time = var[trigger.address||"_"||$account_name||"_predicted_lock_time"] otherwise trigger.data.lock_time;
        // make weekly accounting? (removing the needed coin reserved to pay interets from the pool)
        if ( timestamp > $temp_next_accounting_time )
        {
            $cods_available_from_pool = round(var["pool_balance"] * $YEARLY_INTEREST_P100_FROM_POOL / 100);
            $pool_balance = $temp_pool_balance - $cods_available_from_pool;
            $next_accounting_time = $temp_next_accounting_time + $ACCOUNTING_PERIOD;
            $interest_next_accounting = 0;
        }
        else
        {
            $pool_balance = $temp_pool_balance;
            $next_accounting_time = $temp_next_accounting_time;
            $interest_next_accounting = $temp_interest_next_accounting;
        }
    }",
        "messages": {
            "cases": [
                {
                    "if": "{ !!trigger.data.create}",
                    "init": "{
                }",
                    "messages": [
                        {
                            "app": "asset",
                            "payload": {
                                "cap": "{$TOTAL_CODS_AMOUNT}",
                                "is_private": false,
                                "is_transferrable": true,
                                "fixed_denominations": false,
                                "auto_destroy": false,
                                "cosigned_by_definer": false,
                                "issued_by_definer_only": true,
                                "spender_attested": false
                            }
                        },
                        {
                            "app": "state",
                            "state": "{
                            var["cods_id"] = response_unit;
                            var["block_until"] = timestamp + $GIVEAWAY_PERIOD;
                            var["block_until_nice"] = timestamp_to_string(timestamp + $GIVEAWAY_PERIOD);
                            var["next_accounting_time"] = timestamp + $ACCOUNTING_PERIOD;
                            var["pool_balance"] = $TOTAL_CODS_AMOUNT;
                        }"
                        }
                    ]
                },
                {
                    "if": "{ !!trigger.data.claim }",
                    "init": "{
                    
                    if (!!$user_bytes or !!$user_cods)
                        bounce ($account_name||" for the address "||trigger.address||" already exist, use another address or another 'account_name' !");
                    // Amount received to be blocked to receive free coins
                        $received_bytes = trigger.output[[asset=base]].amount - 2000;
                    // free coin computation
                        $remaining_time = var["block_until"] - timestamp;
                        if ($remaining_time<0)
                            bounce ("Sorry, The free CODs offering is finished !");
                        $elapsed_time = $GIVEAWAY_PERIOD - $remaining_time;
                        $elapsed_days = round($elapsed_time/$DAY);
                        $remaining_days = round($remaining_time/$DAY);
                        $bonus = $MAX_BONUS_P100 - ($elapsed_days * $DAILY_BONUS_REDUCTION_P100);
                        $unfair_free_cods = $received_bytes * ($bonus / 100);
                        
                    // robin hood effect, steal the riches and give to the ... interest pot.
                        $free_cods = round($unfair_free_cods * (1 - (0.04 * ln($received_bytes) - 0.31)));
                        //$new_interest = $free_cods * (0.7 * ln($user_predicted_lock_time) + 1.5); // longer stake => bigger return
                    }",
                    "messages": [
                        {
                            "app": "state",
                            "state": "{
                        var["interest_next_accounting"] = $interest_next_accounting + $new_interest;
                        var["pool_balance"] = $pool_balance - $free_cods;
                        $key = trigger.address||"_"||$account_name;
                        var[$key||"_bytes"] = $received_bytes;
                        var[$key||"_cods"] = $free_cods;
                        var[$key||"_stake_start"] = $user_stake_start;
                        var[$key||"_predicted_lock_time"] = $user_predicted_lock_time;
                        response["message"] = "Your "||$received_bytes||" bytes are safe with us until: "||var["block_until_nice"]||". You will receive "||$free_cods||" free CODs. You still have "||$remaining_days||" days to claim more CODs. Actual bonus is "||$bonus||"% of your bytes.";
                        }"
                        }
                    ]
                },
                {
                    "if": "{ !!trigger.data.cancel_claim }",
                    "init": "{
                    if (!$user_bytes)
                        bounce ("Nothing to cancel ! are you using the right address ?");
                    $predicted_interest = $user_cods * (0.7 * ln($user_predicted_lock_time) + 1.5); 
                    }",
                    "messages": [
                        {
                            "app": "payment",
                            "payload": {
                                "asset": "base",
                                "outputs": [
                                    {
                                        "address": "{trigger.address}",
                                        "amount": "{ $user_bytes }"
                                    }
                                ]
                            }
                        },
                        {
                            "app": "state",
                            "state": "{
                            var["interest_next_accounting"] = $interest_next_accounting - $predicted_interest;
                            var["pool_balance"] = $pool_balance + $user_cods;
                            var[$key||"_bytes"] = false; // back to user
                            var[$key||"_cods"] = false;  // back to the pool
                            var[$key||"_stake_start"] = false;
                            response["message"] = "Your requested your "||$user_bytes||" bytes back. YOu have lost your "||$user_cods||" CODs.";
                        }"
                        }
                    ]
                },
                {
                    "if": "{ !!trigger.data.get_bytes_back }",
                    "init": "{
                    if (!$user_bytes)
                        bounce ($account_name||" with the address "||trigger.address||" do NOT exist !");
                    if ( timestamp < var["block_until"] )
                        bounce ("Too early to get your bytes back, except if you ready to loose your CODs, in this case use 'cancel_claim'.");
                    }",
                    "messages": [
                        {
                            "app": "payment",
                            "payload": {
                                "asset": "base",
                                "outputs": [
                                    {
                                        "address": "{ trigger.address }",
                                        "amount": "{ $user_bytes }"
                                    }
                                ]
                            }
                        },
                        {
                            "app": "state",
                            "state": "{
                        var[trigger.address||"_"||$account_name||"_bytes"] = false;
                        response["message"] = "Your "||$user_bytes||" bytes have been sent back to you, you have now "||$user_cods||" CODs staking since "||$user_stake_start||".";
                        }"
                        }
                    ]
                },
                {
                    "if": "{ !!trigger.data.stake }",
                    "init": "{
                    if (trigger.output[[asset!=base]].asset != $cods )
                        bounce ("You can only stake CODs ('"||$cods||"'.");
                    if (!!$user_cods)
                        bounce ($account_name||" for the address "||trigger.address||" already exist, use another address or another 'account_name' !");
                    $received_cods = trigger.output[[asset!=base]].amount;
                    $new_interest = $received_cods * (0.7 * ln($user_predicted_lock_time) + 1.5); // longer stake => bigger return
                    }",
                    "messages": [
                        {
                            "app": "state",
                            "state": "{
                                var["interest_next_accounting"] = $interest_next_accounting + $new_interest;
                                $key = trigger.address||"_"||$account_name;
                                var[$key||"_cods"] = $received_cods;
                                var[$key||"_stake_start"] = $user_stake_start;
                                var[$key||"_predicted_lock_time"] = $user_predicted_lock_time;
                                response["message"] = $received_cods||" CODs in stake until "||timestamp_to_string($user_stake_start + $user_predicted_lock_time)||".";
                            }"
                        }
                    ]
                },
                {
                    "if": "{ !!trigger.data.unstake }",
                    "init": "{
                    if (!$user_cods)
                        bounce ($account_name||" with the address "||trigger.address||" do NOT exist !");
                    if (!!$user_bytes)
                        bounce ("Cannot unstake while having bytes in the system, please use 'get_bytes_back' or 'cancel_claim'!");
                    $too_early = timestamp < $user_stake_start + $user_predicted_lock_time;
                    if ( !!$too_early and !trigger.data.use_force )
                        bounce ("Your defined staking period ends in "||($user_stake_start + $user_predicted_lock_time-timestamp)/24/60/60||" days. To force the unstaking and loose a big part of your interests use 'use_force' !");
                    // compute interets 
                    $predicted_interest = $user_cods * (0.7 * ln($user_predicted_lock_time) + 1.5); 
                }",
                    "messages": [
                        {
                            "app": "state",
                            "state": "{
                            var["interest_next_accounting"] = $interest_next_accounting - $predicted_interest;
                            $key = trigger.address||"_"||$account_name;
                            var[$key||"_cods"] = false;
                            var[$key||"_stake_start"] = false;
                            var[$key||"_predicted_lock_time"] = false;
                            response["message"] = "Your "||$user_cods||" CODs have been sent to you, you have now.";
                        }"
                        }
                    ]
                },
                {
                    "init": "{
                if (!$user_cods)
                    bounce ($account_name||" with the address "||trigger.address||" do NOT exist !");
                $too_early = timestamp < $user_stake_start + $user_predicted_lock_time;
            
                // compute interets 
                $predicted_interest = $user_cods * (0.7 * ln($user_predicted_lock_time) + 1.5); 
                }",
                    "messages": [
                        {
                            "app": "state",
                            "state": "{
                            var["interest_next_accounting"] = 0;
                            
                            var["pool_balance"] = $pool_balance + $user_cods;
                            $key = trigger.address||"_"||$account_name;
                            var[$key||"_cods"] = $received_cods;
                            var[$key||"_stake_start"] = $user_stake_start;
                            var[$key||"_predicted_lock_time"] = $user_predicted_lock_time;
                            response["message"] = $received_cods||" CODs in stake until "||timestamp_to_string($user_stake_start + $user_predicted_lock_time)||".";
                        }"
                        }
                    ]
                }
            ]
        }
    }
]