[
    "autonomous agent",
    {
        "doc_url": "https://pythagorean.org/governance.json",
        "getters": "{
        $get_parsed_value = ($name, $value) => {
            $value
        };
    }",
        "init": "{
        $challenging_period = params.challenging_period OTHERWISE 3*24*3600;
        // one cannot withdraw for this period after voting for a winning value
        $freeze_period = params.freeze_period OTHERWISE 30*24*3600;
        $aa = params.aa;
        if (!$aa)
            bounce("no aa");
        $state = var[$aa]['state'];
        $asset = $state.asset0;
        
        $names = ['swap_fee', 'arb_profit_tax', 'min_s0_share', 'adjustment_period', 'token_share_threshold', 'presale_period', 'auction_price_halving_period', 'add_price_aa', 'add_preipo', 'change_price_aa'];
        
        $is_allowed_name = $name => {
            length(filter($names, 20, $n => $n == $name)) == 1
        };
        $get_value_key = $value => $value;
    }",
        "messages": {
            "cases": [
                {
                    "if": "{ trigger.data.name AND trigger.data.commit }",
                    "init": "{
                    $name = trigger.data.name;
                    if ($name == 'add_price_aa'){
                        $price_aa = trigger.data.price_aa;
                        $full_name = $name||$price_aa;
                    }
                    else if ($name == 'change_price_aa'){
                        $a = trigger.data.asset;
                        $full_name = $name||$a;
                    }
                    else if ($name == 'add_preipo'){
                        $symbol = trigger.data.symbol;
                        $initial_auction_price = trigger.data.initial_auction_price;
                        $max_tokens = trigger.data.max_tokens;
                        $full_name = $name||$symbol||'_'||$initial_auction_price||'_'||$max_tokens;
                    }
                    else
                        $full_name = $name;
                    $leader = var['leader_' || $full_name];
                    $current_value = var[$full_name];
                    require(exists($leader), "no leader");
                    if (exists($current_value) AND $leader == $current_value)
                        bounce("already equal to leader");
                    require(var['challenging_period_start_ts_' || $full_name] + $challenging_period < timestamp OR var['support_' || $full_name || '_' || $leader] > $state.s0/2, "challenging period not expired yet");
                }",
                    "messages": [
                        {
                            "app": "payment",
                            "payload": {
                                "asset": "base",
                                "outputs": [
                                    {
                                        "address": "{$aa}",
                                        "amount": 5000
                                    }
                                ]
                            }
                        },
                        {
                            "app": "data",
                            "payload": {
                                "name": "{$name}",
                                "value": "{$leader}",
                                "price_aa": "{$name == 'add_price_aa' ? $price_aa : ''}",
                                "asset": "{$name == 'change_price_aa' ? $a : ''}",
                                "symbol": "{$name == 'add_preipo' ? $symbol : ''}",
                                "initial_auction_price": "{$name == 'add_preipo' ? $initial_auction_price : ''}",
                                "max_tokens": "{$name == 'add_preipo' ? $max_tokens : ''}"
                            }
                        },
                        {
                            "app": "state",
                            "state": "{
                            var[$full_name] = $leader;
                        }"
                        }
                    ]
                },
                {
                    "if": "{ trigger.data.name }",
                    "init": "{
                    $balance = var['balance_' || trigger.address] + trigger.output[[asset=$asset]];
                    if (!$balance)
                        bounce("you have no deposited balance and cannot vote");
                    $name = trigger.data.name;
                    $value = trigger.data.value; // can be empty to remove one's vote
                    if (!$is_allowed_name($name))
                        bounce("unknown name: " || $name);
                    if ($name == 'add_price_aa'){
                        $price_aa = trigger.data.price_aa;
                    //    require(is_valid_address($price_aa), "not a valid address");
                        require(typeof($price_aa#1.$get_target_price()) == 'number', "bad price");
                        $full_name = $name||$price_aa;
                    }
                    else if ($name == 'change_price_aa'){
                        $a = trigger.data.asset;
                        require(var[$aa]['asset_'||$a], "not a valid asset");
                        $full_name = $name||$a;
                    }
                    else if ($name == 'add_preipo'){
                        $symbol = trigger.data.symbol;
                        $initial_auction_price = trigger.data.initial_auction_price;
                        $max_tokens = trigger.data.max_tokens;
                        require($symbol, "no symbol");
                        require($initial_auction_price > 0, "bad initial price");
                        require(length($symbol) <= 10, "symbol too long");
                        require(is_integer($max_tokens) AND $max_tokens > 0, "bad max_tokens");
                        $full_name = $name||$symbol||'_'||$initial_auction_price||'_'||$max_tokens;
                    }
                    else
                        $full_name = $name;
                    if (exists($value)){
                        if ($name == 'swap_fee' OR $name == 'min_s0_share')
                            require(typeof($value) == 'number' AND $value >= 0 AND $value < 1, "invalid value");
                        if ($name == 'arb_profit_tax' OR $name == 'token_share_threshold')
                            require(typeof($value) == 'number' AND $value >= 0, "invalid value");
                        if ($name == 'adjustment_period' OR $name == 'presale_period' OR $name == 'auction_price_halving_period')
                            require(is_integer($value) AND $value > 0, "invalid value");
                        if ($name == 'add_price_aa' OR $name == 'add_preipo')
                            require($value == 'yes' OR $value == 'no', "invalid value");
                        if ($name == 'change_price_aa'){
                            $price = $value#1.$get_target_price();
                            require(typeof($price) == 'number' OR !exists($price), "bad price"); // false price is also acceptable
                        }
                    }
                }",
                    "messages": [
                        {
                            "app": "state",
                            "state": "{
                            if (trigger.output[[asset=$asset]])
                                var['balance_' || trigger.address] += trigger.output[[asset=$asset]];
                            $prev_choice = var['choice_' || trigger.address || '_' || $full_name];
                            $leader = var['leader_' || $full_name];
                            if (exists($leader) AND exists($prev_choice) AND $prev_choice == $leader AND var['challenging_period_start_ts_' || $full_name] + $challenging_period + $freeze_period > timestamp)
                                bounce("you cannot change your vote yet");
                            var['choice_' || trigger.address || '_' || $full_name] = $value;
                            if (exists($prev_choice)){
                                $prev_choice_key = $get_value_key($prev_choice);
                                var['support_' || $full_name || '_' || $prev_choice_key] -= var['support_' || $full_name || '_' || $prev_choice_key || '_' || trigger.address];
                                var['support_' || $full_name || '_' || $prev_choice_key || '_' || trigger.address] = false;
                            }
                            if (exists($value)){
                                $value_key = $get_value_key($value);
                                var['support_' || $full_name || '_' || $value_key] += $balance;
                                var['support_' || $full_name || '_' || $value_key || '_' || trigger.address] = $balance;
                                if (!exists($leader) OR var['support_' || $full_name || '_' || $value_key] > var['support_' || $full_name || '_' || $get_value_key($leader)]){
                                    var['leader_' || $full_name] = $value;
                                    var['challenging_period_start_ts_' || $full_name] = timestamp;
                                }
                            }
                        }"
                        }
                    ]
                },
                {
                    "if": "{ trigger.data.withdraw }",
                    "init": "{
                    $balance = var['balance_' || trigger.address] + trigger.output[[asset=$asset]];
                    if (!$balance)
                        bounce("you have no deposited balance and cannot withdraw");
                    $amount = trigger.data.amount OTHERWISE $balance;
                    if ($amount > $balance)
                        bounce("your balance is only " || $balance);
                    foreach($names, 12, $name => {
                        if (var['choice_' || trigger.address || '_' || $name])
                            bounce("support for " || $name || " not removed yet");
                    });
                }",
                    "messages": [
                        {
                            "app": "payment",
                            "payload": {
                                "asset": "{$asset}",
                                "outputs": [
                                    {
                                        "address": "{trigger.address}",
                                        "amount": "{ $amount }"
                                    }
                                ]
                            }
                        },
                        {
                            "app": "state",
                            "state": "{
                            var['balance_' || trigger.address] -= $amount;
                        }"
                        }
                    ]
                }
            ]
        }
    }
]