[
"autonomous agent",
{
"doc_url": "https://obyte.org/prediction.json",
"bounce_fees": {
"base": 10000
},
"getters": "{
$get_reserve = ($yes_amount, $no_amount, $draw_amount) => {
$coef = var['coef'] OTHERWISE 1;
$r = ceil($coef * sqrt($yes_amount^2 + $no_amount^2 + $draw_amount^2));
$r
};
$get_price_by_type = ($type) => {
$allow_draw = params.allow_draw OTHERWISE false;
$supply_yes = var['supply_yes'] OTHERWISE 0;
$supply_no = var['supply_no'] OTHERWISE 0;
$supply_draw = var['supply_draw'] OTHERWISE 0;
$coef = var['coef'] OTHERWISE 1;
require($type == 'yes' OR $type == 'no' OR $type == 'draw', "unknown type");
require($allow_draw OR $type != 'draw', "draw token does not exist");
require(($supply_yes + $supply_no + $supply_draw) != 0, "no supply");
$token_amount_by_type = $type == 'yes' ? $supply_yes : $type == 'no' ? $supply_no : $supply_draw;
$price = $coef * ($token_amount_by_type / sqrt($supply_yes^2 + $supply_no^2 + $supply_draw^2));
$price
};
$get_exchange_result = ($yes_amount, $no_amount, $draw_amount) => {
$supply_yes = var['supply_yes'] OTHERWISE 0;
$supply_no = var['supply_no'] OTHERWISE 0;
$supply_draw = var['supply_draw'] OTHERWISE 0;
$allow_draw = params.allow_draw OTHERWISE false;
$current_reserve = var['reserve'] OTHERWISE 0;
$coef = var['coef'] OTHERWISE 1;
$issue_fee = exists(params.issue_fee) ? params.issue_fee : 0.01;
$redeem_fee = exists(params.redeem_fee) ? params.redeem_fee : 0.02;
$arb_profit_tax = exists(params.arb_profit_tax) ? params.arb_profit_tax : 0.9;
$new_supply_yes = $supply_yes + ($yes_amount ? $yes_amount : 0);
$new_supply_no = $supply_no + ($no_amount ? $no_amount : 0);
$new_supply_draw = $supply_draw + ($draw_amount ? $draw_amount : 0);
$new_reserve = $get_reserve($new_supply_yes, $new_supply_no, $new_supply_draw);
$reserve_delta = $new_reserve - $current_reserve;
require($new_supply_yes >= 0 AND $new_supply_no >= 0 AND $new_supply_draw >= 0, "too much redeem?");
require($allow_draw OR $draw_amount == 0, "draw_asset isn't exist");
$reserve_needed = $reserve_delta > 0 ? $reserve_delta : 0;
$payout = $reserve_delta < 0 ? abs($reserve_delta) : 0;
require($payout <= $current_reserve, "too much redeem?");
// calc arb profit fee
if (($supply_yes + $supply_no + $supply_draw) != 0) {
$old_den = sqrt($supply_yes^2 + $supply_no^2 + $supply_draw^2);
$old_yes_price = $coef * ($supply_yes / $old_den);
$old_no_price = $coef * ($supply_no / $old_den);
$old_draw_price = $coef * ($supply_draw / $old_den);
$new_den = sqrt($new_supply_yes^2 + $new_supply_no^2 + $new_supply_draw^2);
$new_yes_price = $coef * ($new_supply_yes / $new_den);
$new_no_price = $coef * ($new_supply_no / $new_den);
$new_draw_price = $coef * ($new_supply_draw / $new_den);
$yes_arb_profit_tax = (abs(($old_yes_price - $new_yes_price) * $yes_amount) / 2) * $arb_profit_tax;
$no_arb_profit_tax = (abs(($old_no_price - $new_no_price) * $no_amount) / 2) * $arb_profit_tax;
$draw_arb_profit_tax = $allow_draw ? (abs(($old_draw_price - $new_draw_price) * $draw_amount) / 2) * $arb_profit_tax : 0;
} else {
$yes_arb_profit_tax = 0;
$no_arb_profit_tax = 0;
$draw_arb_profit_tax = 0;
}
$total_arb_profit_tax = $yes_arb_profit_tax + $no_arb_profit_tax + $draw_arb_profit_tax;
require($yes_arb_profit_tax >= 0 AND $no_arb_profit_tax >= 0 AND $draw_arb_profit_tax >= 0, "negative arb profit tax");
$fee = ceil($reserve_needed * $issue_fee + $payout * $redeem_fee + $total_arb_profit_tax);
$next_coef = $coef * (($new_reserve + $fee) / $new_reserve);
{
reserve_needed: $reserve_needed,
new_reserve: $new_reserve + $fee,
payout: $payout,
fee: $fee,
arb_profit_tax: $total_arb_profit_tax,
next_coef: $next_coef
}
};
$get_token_amount = ($type, $reserve_amount) => {
$reserve_asset = params.reserve_asset OTHERWISE 'base';
$issue_fee = exists(params.issue_fee) ? params.issue_fee : 0.01;
$arb_profit_tax = exists(params.arb_profit_tax) ? params.arb_profit_tax : 0.9;
require($type == 'yes' OR $type == 'no' OR $type == 'draw', "unknown type");
require(params.allow_draw OR $type != 'draw', "draw token does not exist");
require($reserve_amount - ($reserve_asset == 'base' ? 10000 : 0) > 0, "negative amount");
$coef = var['coef'] OTHERWISE 1;
$supply_yes = var['supply_yes'] OTHERWISE 0;
$supply_no = var['supply_no'] OTHERWISE 0;
$supply_draw = var['supply_draw'] OTHERWISE 0;
$network_fee = ($reserve_asset == 'base' ? 10000 : 0);
$fee = ceil($reserve_amount - $network_fee - (($reserve_amount - $network_fee) / (1 + $issue_fee)));
$reserve = var['reserve'] + $reserve_amount - $fee - $network_fee;
$ratio = $reserve^2/$coef^2;
$supply_yes_squared = $supply_yes^2;
$supply_no_squared = $supply_no^2;
$supply_draw_squared = $supply_draw^2;
if ($type == 'yes') {
$prepare_calc = $ratio - $supply_no_squared - $supply_draw_squared;
} else if ($type == 'no') {
$prepare_calc = $ratio - $supply_yes_squared - $supply_draw_squared;
} else {
$prepare_calc = $ratio - $supply_yes_squared - $supply_no_squared;
}
$supply = $type == 'yes' ? $supply_yes : $type == 'no' ? $supply_no : $supply_draw;
$amount = floor(sqrt($prepare_calc) - $supply);
if (($supply_yes + $supply_no + $supply_draw) != 0) {
$old_den = sqrt($supply_yes_squared + $supply_no_squared + $supply_draw_squared);
$old_price = $coef * ($supply / $old_den);
$new_supply = $supply + $amount;
$new_supply_squared = $new_supply^2;
$new_den = sqrt(($type == 'yes' ? $new_supply_squared : $supply_yes_squared) + ($type == 'no' ? $new_supply_squared : $supply_no_squared) + ($type == 'draw' ? $new_supply_squared : $supply_draw_squared));
$new_price = $coef * ($new_supply / $new_den);
$arb_profit_tax_amount = ((abs($old_price - $new_price) * $amount) / 2) * $arb_profit_tax;
$fee_with_arb_profit_tax = ceil($reserve_amount - $network_fee - (($reserve_amount - $network_fee) / (1 + $issue_fee))) + $arb_profit_tax_amount;
$reserve_without_tax_and_fee = var['reserve'] + $reserve_amount - $fee_with_arb_profit_tax - $network_fee;
$new_ratio = $reserve_without_tax_and_fee^2/$coef^2;
if ($type == 'yes') {
$prepare_calc_2 = $new_ratio - $supply_no_squared - $supply_draw_squared;
} else if ($type == 'no') {
$prepare_calc_2 = $new_ratio - $supply_yes_squared - $supply_draw_squared;
} else {
$prepare_calc_2 = $new_ratio - $supply_yes_squared - $supply_no_squared;
}
return floor(sqrt($prepare_calc_2) - $supply);
} else {
return $amount;
}
};
}",
"init": "{
// params
$event = params.event OTHERWISE '';
require(length($event) >= 3 AND length($event) <= 128, "additional description cannot be over 128 chars");
$oracle = params.oracle OTHERWISE 'F4KHJUCLJKY4JV7M5F754LAJX4EB7M4N'; // for testnet
require($oracle AND is_valid_address($oracle), "oracle isn't valid");
$comparison = params.comparison OTHERWISE "==";
require($comparison == "==" OR $comparison == ">" OR $comparison == ">=" OR $comparison == "<" OR $comparison == "<=" OR $comparison == "!=", "operation is unknown");
$feed_name = params.feed_name OTHERWISE '';
require(length($feed_name) > 0 AND $feed_name != "none", "feed_name isn't valid");
$reserve_asset = params.reserve_asset OTHERWISE 'base';
require(asset[$reserve_asset].exists, "no such asset: " || $reserve_asset);
$allow_draw = params.allow_draw OTHERWISE false;
$datafeed_draw_value = params.datafeed_draw_value OTHERWISE 'none';
$datafeed_value = params.datafeed_value;
require(exists($datafeed_value), "datafeed_value does not exist");
$end_of_trading_period = params.end_of_trading_period OTHERWISE 0;
require(is_integer($end_of_trading_period) AND $end_of_trading_period > 0, "end_of_trading_period must be integer");
$waiting_period_length = params.waiting_period_length OTHERWISE 5 * 24 * 3600;
require(is_integer($waiting_period_length) AND $waiting_period_length >= 0, "trading period must be longer than a day");
$issue_fee = exists(params.issue_fee) ? params.issue_fee : 0.01;
require($issue_fee >= 0 AND $issue_fee < 1, "issue_fee isn't valid");
$redeem_fee = exists(params.redeem_fee) ? params.redeem_fee : 0.02;
require($redeem_fee >= 0 AND $redeem_fee < 1, "redeem_fee isn't valid");
// helpers
$ready = var['yes_asset'] AND var['no_asset'] AND (var['draw_asset'] OR !$allow_draw);
$result = var['result']; // yes/no/draw
$yes_asset = var['yes_asset'];
$no_asset = var['no_asset'];
$draw_asset = var['draw_asset'];
$end_of_waiting_period = $end_of_trading_period + $waiting_period_length;
$network_fee = ($reserve_asset == 'base') ? 10000 : 0;
$reserve = var['reserve'] OTHERWISE 0;
$reserve_amount = trigger.output[[asset=$reserve_asset]];
$type = trigger.data.type OTHERWISE false;
if ($type) {
require($type == 'yes' OR $type == 'no' OR $type == 'draw', "unknown type");
}
}",
"messages": {
"cases": [
{
"if": "{!$ready AND trigger.data.define}",
"init": "{
$define_type = $yes_asset ? ($no_asset ? "draw_asset" : "no_asset") : "yes_asset";
$define_asset_forwarder = 'E4BAASPOCW6WHXSUOY2XEKXKA42RRD5I';
require(($define_type == 'draw_asset' AND $allow_draw) OR $define_type == 'no_asset' OR $define_type == 'yes_asset', "unknown define type");
require(!var[$define_type], "asset already defined");
}",
"messages": [
{
"app": "asset",
"payload": {
"is_private": false,
"is_transferrable": true,
"auto_destroy": false,
"fixed_denominations": false,
"issued_by_definer_only": true,
"cosigned_by_definer": false,
"spender_attested": false
}
},
{
"if": "{trigger.data.factory AND !$yes_asset}",
"app": "data",
"payload": {
"factory": "{trigger.data.factory}"
}
},
{
"if": "{trigger.data.factory AND !$yes_asset}",
"app": "payment",
"payload": {
"asset": "base",
"outputs": [
{
"address": "{$define_asset_forwarder}",
"amount": 4000
}
]
}
},
{
"if": "{trigger.data.factory AND $yes_asset AND !$no_asset}",
"app": "data",
"payload": {
"yes_asset": "{$yes_asset}",
"allow_draw": "{params.allow_draw}"
}
},
{
"if": "{trigger.data.factory AND $yes_asset AND !$no_asset}",
"app": "payment",
"payload": {
"asset": "base",
"outputs": [
{
"address": "{trigger.data.factory}",
"amount": 4000
}
]
}
},
{
"if": "{trigger.data.factory AND $yes_asset AND $no_asset AND !$draw_asset AND $allow_draw}",
"app": "data",
"payload": {
"no_asset": "{$no_asset}"
}
},
{
"if": "{trigger.data.factory AND $yes_asset AND $no_asset AND !$draw_asset AND $allow_draw}",
"app": "payment",
"payload": {
"asset": "base",
"outputs": [
{
"address": "{trigger.data.factory}",
"amount": 4000
}
]
}
},
{
"app": "state",
"state": "{
var[$define_type] = response_unit;
response[$define_type] = response_unit;
}"
}
]
},
{
"if": "{$ready AND !$result AND !exists(trigger.data.claim_profit) AND (((trigger.output[[asset=$reserve_asset]] > $network_fee) AND (trigger.data.yes_amount OR trigger.data.no_amount OR trigger.data.draw_amount OR trigger.data.type)) OR trigger.output[[asset=$yes_asset]] > 0 OR trigger.output[[asset=$no_asset]] > 0 OR ($allow_draw AND trigger.output[[asset=$draw_asset]] > 0))}",
"init": "{
if (trigger.data.to AND !is_valid_address(trigger.data.to))
bounce("bad to address");
require($allow_draw OR !exists(trigger.data.draw_amount), "draw asset does not exist");
require(timestamp <= $end_of_trading_period OR timestamp >= $end_of_waiting_period, "the trading period is closed");
if ((trigger.data.yes_amount OR trigger.data.no_amount OR trigger.data.draw_amount OR trigger.output[[asset=$yes_asset]] > 0 OR trigger.output[[asset=$no_asset]] > 0 OR ($allow_draw AND trigger.output[[asset=$draw_asset]] > 0)) AND trigger.data.type) {
bounce("both type and amount");
}
$min_expected_amount = trigger.data.min_expected_amount OTHERWISE 0;
if ($type AND (!is_integer($min_expected_amount) OR $min_expected_amount < 0)) {
bounce("invalid min_expected_amount");
}
$to = trigger.data.to OTHERWISE trigger.address;
$yes_amount = (!$type OR $type != 'yes') ? trigger.data.yes_amount OTHERWISE -trigger.output[[asset=$yes_asset]] : $get_token_amount('yes', $reserve_amount);
$no_amount = (!$type OR $type != 'no') ? trigger.data.no_amount OTHERWISE -trigger.output[[asset=$no_asset]] : $get_token_amount('no', $reserve_amount);
$draw_amount = $allow_draw ? ((!$type OR $type != 'draw') ? trigger.data.draw_amount OTHERWISE -trigger.output[[asset=$draw_asset]] : $get_token_amount('draw', $reserve_amount)) : 0;
if (trigger.data.yes_amount AND (!is_integer(trigger.data.yes_amount) OR trigger.data.yes_amount <= 0))
bounce("invalid number of yes_amount");
if (trigger.data.no_amount AND (!is_integer(trigger.data.no_amount) OR trigger.data.no_amount <= 0))
bounce("invalid number of no_amount");
if ($allow_draw AND trigger.data.draw_amount AND (!is_integer(trigger.data.draw_amount) OR trigger.data.draw_amount <= 0))
bounce("invalid number of draw_amount");
if (trigger.data.yes_amount AND trigger.output[[asset=$yes_asset]] > 0)
bounce("both yes_amount param and amount");
if (trigger.data.no_amount AND trigger.output[[asset=$no_asset]] > 0)
bounce("both no_amount param and amount");
if ($allow_draw AND trigger.data.draw_amount AND trigger.output[[asset=$draw_asset]] > 0)
bounce("both draw_amount param and amount");
$res = $get_exchange_result($yes_amount, $no_amount, $draw_amount);
$payout = floor($res.payout + $reserve_amount - $res.reserve_needed - $res.fee - $network_fee);
if ($type) {
$amount = $type == 'yes' ? $yes_amount : ($type == 'no' ? $no_amount : $draw_amount);
require($amount >= $min_expected_amount, "amount less than minimum");
}
if ($res.reserve_needed > 0) {
require($res.reserve_needed + $res.fee + $network_fee <= $reserve_amount, "expected reserve amount: " || ($res.reserve_needed + $res.fee + $network_fee));
}
}",
"messages": [
{
"if": "{$yes_amount > 0}",
"app": "payment",
"payload": {
"asset": "{$yes_asset}",
"outputs": [
{
"address": "{$to}",
"amount": "{$yes_amount}"
}
]
}
},
{
"if": "{$no_amount > 0}",
"app": "payment",
"payload": {
"asset": "{$no_asset}",
"outputs": [
{
"address": "{$to}",
"amount": "{$no_amount}"
}
]
}
},
{
"if": "{$draw_amount > 0 AND $allow_draw}",
"app": "payment",
"payload": {
"asset": "{$draw_asset}",
"outputs": [
{
"address": "{$to}",
"amount": "{$draw_amount}"
}
]
}
},
{
"if": "{$payout > 0}",
"app": "payment",
"payload": {
"asset": "{$reserve_asset}",
"outputs": [
{
"address": "{$to}",
"amount": "{$payout}"
}
]
}
},
{
"app": "state",
"state": "{
var['reserve'] = $res.new_reserve;
var['coef'] = $res.next_coef;
response['next_coef'] = $res.next_coef;
if ($payout > 0) {
response['payout'] = $payout;
}
if ($res.fee > 0){
response['fee'] = $res.fee;
}
response['arb_profit_tax'] = $res.arb_profit_tax;
var['supply_yes'] += $yes_amount;
var['supply_no'] += $no_amount;
if ($allow_draw) {
var['supply_draw'] += $draw_amount;
}
}"
}
]
},
{
"if": "{$ready AND trigger.data.commit AND !$result}",
"init": "{
require(timestamp > $end_of_trading_period, "trading period has not yet ended");
$current_datafeed_value = data_feed[[oracles=$oracle, feed_name=$feed_name, ifnone='none']];
require($current_datafeed_value != 'none', "data_feed is empty");
require(timestamp > $end_of_trading_period, "trading period has not ended yet");
require(timestamp < $end_of_waiting_period, "it's late, the waiting period has passed");
if ($comparison == '>')
$datafeed_comparison = $current_datafeed_value > $datafeed_value;
else if ($comparison == '<')
$datafeed_comparison = $current_datafeed_value < $datafeed_value;
else if ($comparison == '!=')
$datafeed_comparison = $current_datafeed_value != $datafeed_value;
else if ($comparison == '==')
$datafeed_comparison = $current_datafeed_value == $datafeed_value;
else if ($comparison == '>=')
$datafeed_comparison = $current_datafeed_value >= $datafeed_value;
else if ($comparison == '<=')
$datafeed_comparison = $current_datafeed_value <= $datafeed_value;
else
bounce('Comparison operator not found');
if ($datafeed_comparison) {
$res = 'yes';
} else if ($allow_draw AND $current_datafeed_value == $datafeed_draw_value) {
$res = 'draw';
} else {
$res = 'no';
}
}",
"messages": [
{
"app": "state",
"state": "{
var['result'] = $res;
response['messages'] = "The result is committed";
response['result'] = $res;
}"
}
]
},
{
"if": "{$ready AND trigger.data.claim_profit}",
"init": "{
$yes_amount = trigger.output[[asset=$yes_asset]];
$no_amount = trigger.output[[asset=$no_asset]];
$draw_amount = $allow_draw ? trigger.output[[asset=$draw_asset]] : 0;
require(($reserve_asset == 'base' AND $reserve_amount == $network_fee) OR ($reserve_asset != 'base' AND $reserve_amount == 0), "should not send a reserve");
require($result, "no results yet");
$winner_amount = $result == 'yes' ? $yes_amount : $result == 'no' ? $no_amount : $draw_amount;
require($winner_amount > 0, "you are sending not a winner token");
$winner_supply = $result == 'yes' ? var['supply_yes'] : $result == 'no' ? var['supply_no'] : var['supply_draw'];
require($winner_supply > 0, "winner supply < 0");
$price_winner_by_reserve = $reserve / $winner_supply;
$payout = floor($winner_amount * $price_winner_by_reserve);
$to = trigger.data.to OTHERWISE trigger.address;
}",
"messages": [
{
"if": "{ $payout > 0 }",
"app": "payment",
"payload": {
"asset": "{$reserve_asset}",
"outputs": [
{
"address": "{$to}",
"amount": "{$payout}"
}
]
}
},
{
"app": "state",
"state": "{
response["Your profit"] = $payout;
if ($yes_amount > 0) {
var['supply_yes'] -= $yes_amount;
}
if ($no_amount > 0) {
var['supply_no'] -= $no_amount;
}
if ($allow_draw AND $draw_amount > 0) {
var['supply_draw'] -= $draw_amount;
}
}"
}
]
}
]
}
}
]