Definition: [
"autonomous agent",
{
"doc_url": "https://counterstake.org/bridge-import-governance.json",
"getters": "{
$get_oracles = $oracles_string => {
$pairs = split($oracles_string, " ");
if (length($pairs) > 3)
bounce("too many oracles");
$oracles_data = map($pairs, 3, $pair => {
$oracle = substring($pair, 0, 32);
if (!is_valid_address($oracle))
bounce("invalid oracle address: " || $oracle);
$op = substring($pair, 32, 1);
if ($op != '*' AND $op != '/')
bounce("invalid format of oracles, should be oracle*feed_name or oracle/feed_name");
$feed_name = substring($pair, 33);
{
oracle: $oracle,
feed_name: $feed_name,
op: $op,
}
});
$oracles_data
};
$get_challenging_periods = $periods_string => {
$periods = split($periods_string, " ");
if (length($periods) > 20)
bounce("too many periods");
$prev = {period: 0};
map($periods, 20, $period => {
$nPeriod = +$period;
if ($nPeriod <= 0 OR $nPeriod > 3*365*24)
bounce("bad challenging period: " || $period);
if ($nPeriod < $prev.period)
bounce("subsequent periods cannot get shorter");
$prev.period = $nPeriod;
$nPeriod
})
};
$get_parsed_value = ($name, $value) => {
if ($name == 'oracles')
return $get_oracles($value);
if ($name == 'challenging_periods' OR $name == 'large_challenging_periods')
return $get_challenging_periods($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;
$import_aa = params.import_aa;
if (!$import_aa)
bounce("no import_aa");
$asset = var[$import_aa]['asset'];
$names = ['ratio', 'counterstake_coef', 'min_tx_age', 'min_stake', 'large_threshold', 'challenging_periods', 'large_challenging_periods', 'min_price', 'oracles'];
$is_allowed_name = $name => {
length(filter($names, 20, $n => $n == $name)) == 1
};
$get_value_key = $value => {
$key_len = length('support_' || 'oracles' || '_' || $value || '_') + 32;
($key_len > 128) ? sha256($value) : $value
};
}",
"messages": {
"cases": [
{
"if": "{ trigger.data.name AND trigger.data.commit }",
"init": "{
$name = trigger.data.name;
$leader = var['leader_' || $name];
$current_value = var[$name];
if (!exists($leader)) // can be 0
bounce("no leader");
if (exists($current_value) AND $leader == $current_value)
bounce("already equal to leader");
if (var['challenging_period_start_ts_' || $name] + $challenging_period > timestamp)
bounce("challenging period not expired yet");
}",
"messages": [
{
"app": "payment",
"payload": {
"asset": "base",
"outputs": [
{
"address": "{$import_aa}",
"amount": 5000
}
]
}
},
{
"app": "data",
"payload": {
"name": "{$name}",
"value": "{$get_parsed_value($name, $leader)}"
}
},
{
"app": "state",
"state": "{
var[$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 (exists($value)){
if ($name == 'ratio' AND !(typeof($value) == 'number' AND $value > 0))
bounce("invalid value");
if ($name == 'counterstake_coef' AND !(typeof($value) == 'number' AND $value > 1))
bounce("invalid value");
if ($name == 'min_stake' AND !(is_integer($value) AND $value >= 0))
bounce("invalid value");
if ($name == 'min_tx_age' AND !(is_integer($value) AND $value >= 0))
bounce("invalid value");
if ($name == 'large_threshold' AND !(is_integer($value) AND $value >= 0))
bounce("invalid value");
if ($name == 'min_price' AND !(typeof($value) == 'number' AND $value >= 0))
bounce("invalid value");
if ($name == 'oracles' OR $name == 'challenging_periods' OR $name == 'large_challenging_periods')
$data = $get_parsed_value($name, $value); // will bounce if the format is bad
}
}",
"messages": [
{
"app": "state",
"state": "{
if (trigger.output[[asset=$asset]])
var['balance_' || trigger.address] += trigger.output[[asset=$asset]];
$prev_choice = var['choice_' || trigger.address || '_' || $name];
$leader = var['leader_' || $name];
if (exists($leader) AND exists($prev_choice) AND $prev_choice == $leader AND var['challenging_period_start_ts_' || $name] + $challenging_period + $freeze_period > timestamp)
bounce("you cannot change your vote yet");
var['choice_' || trigger.address || '_' || $name] = $value;
if (exists($prev_choice)){
$prev_choice_key = $get_value_key($prev_choice);
var['support_' || $name || '_' || $prev_choice_key] -= var['support_' || $name || '_' || $prev_choice_key || '_' || trigger.address];
var['support_' || $name || '_' || $prev_choice_key || '_' || trigger.address] = false;
}
if (exists($value)){
$value_key = $get_value_key($value);
var['support_' || $name || '_' || $value_key] += $balance;
var['support_' || $name || '_' || $value_key || '_' || trigger.address] = $balance;
if (!exists($leader) OR var['support_' || $name || '_' || $value_key] > var['support_' || $name || '_' || $get_value_key($leader)]){
var['leader_' || $name] = $value;
var['challenging_period_start_ts_' || $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;
}"
}
]
}
]
}
}
]