[
"autonomous agent",
{
"doc_url": "https://oswap.io/oswap-token-arb.json",
"getters": "{
}",
"init": "{
$reversed = params.reversed;
$token_aa = params.oswap_token_aa;
$v2_aa = params.oswap_v2_aa;
$v2_params = definition[$v2_aa][1].params;
$x_asset = $v2_params.x_asset;
$y_asset = $v2_params.y_asset;
$get_token_param = ($name, $default) => {
$value = var[$token_aa][$name];
exists($value) ? $value : $default
};
$get_v2_param = ($name, $default) => {
$value = var[$v2_aa][$name];
exists($value) ? $value : (exists($v2_params[$name]) ? $v2_params[$name] : $default)
};
$get_shifts = () => {
$mid_price = $get_v2_param('mid_price', 0); // price of x_asset in terms of y_asset
if ($mid_price){
$alpha = $get_v2_param('alpha', 0.5);
$beta = 1 - $alpha;
$gamma = $get_v2_param('price_deviation', 0);
$lp_shares = var[$v2_aa]['lp_shares'];
$s_curve = $lp_shares.linear * $lp_shares.coef;
$x0 = $s_curve / $mid_price^$beta / $gamma;
$y0 = $x0 * $mid_price;
}
// else{
// $x0 = 0;
// $y0 = 0;
// }
{x0: $x0, y0: $y0}
};
$get_denom = ($balances, $l_balances, $shifts, $pxy, $beta) => {
$leverages = [2, 5, 10, 20, 50, 100];
// account for leveraged positions
$L_sums = {x: 0};
foreach($leverages, 6, $L => {
$L_sums.x = $L_sums.x + ($L - 1) * ($l_balances[$L||'x'].balance + $l_balances[-$L||'x'].balance / $pxy);
});
$denom = $beta * ($balances.x + $shifts.x0) - $L_sums.x;
// log({denom: $denom, sum: $L_sums.x, share: $L_sums.x/$denom});
require($denom > 0, "negative denom " || $denom);
$denom
};
$get_available_balance = ($asset) => balance[$asset] - ($asset == 'base' ? 10000 : 0);
$scale_amounts_down_if_necessary = ($amounts, $x_balance, $y_balance) => {
if ($amounts.x > $x_balance AND $amounts.y > $y_balance){
$x_factor = $x_balance/$amounts.x;
$y_factor = $y_balance/$amounts.y;
if ($x_factor >= $y_factor){
$amounts.x = $x_balance;
$amounts.y = floor($x_factor * $amounts.y);
}
else {
$amounts.y = $y_balance;
$amounts.x = floor($y_factor * $amounts.x);
}
log('scaled down to', $amounts);
}
};
}",
"messages": {
"cases": [
{
"if": "{ trigger.data.arb}",
"init": "{
$share = trigger.data.share OTHERWISE 1; // for incomplete arb
$precalculated = trigger.data.amount AND trigger.data.from;
if (!$precalculated) {
$token_fee = $get_token_param('swap_fee', 0.003);
$v2_fee = $get_v2_param('swap_fee', 0.003);
$token_state = var[$token_aa]['state'];
$p1 = $token_aa#7.$get_price();
$p1x = $reversed ? 1/$p1 : $p1;
$balances = var[$v2_aa]['balances'];
$l_balances = var[$v2_aa]['leveraged_balances'];
$shifts = $get_shifts();
$alpha = $get_v2_param('alpha', 0.5);
$beta = 1 - $alpha;
$p2 = $alpha/$beta * ($balances.y + $shifts.y0) / ($balances.x + $shifts.x0);
$p2_oswap = $reversed ? 1/$p2 : $p2;
$denom1 = ($token_state.s0 - $token_state.supply)/2;
$denom2 = $get_denom($balances, $l_balances, $shifts, $p2, $beta);
$Lambda = $get_v2_param('pool_leverage', 1);
$x_balance = $get_available_balance($x_asset);
$y_balance = $get_available_balance($y_asset);
$amounts = {x: 0, y: 0};
// profitable to buy x on v2 pool and sell on token AA
if ($p2 * (1 + $v2_fee) < $p1x * (1 - $token_fee)){
$p2_plus_fee = $p2 * (1 + $v2_fee);
$p1x_minus_fee = $p1x * (1 - $token_fee);
$amounts.x = floor(($p1x_minus_fee - $p2_plus_fee)/$p1x_minus_fee / (1/$denom2 + 1/$denom1));
$amounts.y = floor($p1x_minus_fee * $amounts.x); // overestimate
$scale_amounts_down_if_necessary($amounts, $x_balance, $y_balance);
$final_p = $p2 * (1 + $amounts.x/$denom2 * $share);
// log({p1: $p1, p2: $p2, p1_minus_fee: $p1_minus_fee, p2_plus_fee: $p2_plus_fee, final_p: $final_p, denom2: $denom2, amounts: $amounts});
if ($amounts.y <= $y_balance){
$from = 'v2y';
$asset = $y_asset;
$amount = $amounts.y;
$address = $v2_aa;
$data = {
final_price: $final_p,
hops: [
{ // next oswap in the chain
address: $token_aa,
change_address: this_address,
data: {to: this_address},
},
]
};
}
else{
$from = 'tokenx';
$asset = $x_asset;
$amount = $amounts.x;
$address = $token_aa;
$data = {
hops: [
{
address: $v2_aa,
data: {
final_price: $final_p,
}
},
{
address: this_address
}
]
};
}
}
// profitable to buy x on token AA and sell on v2 pool
else if ($p2 * (1 - $v2_fee) > $p1x * (1 + $token_fee)){
$p2_minus_fee = $p2 * (1 - $v2_fee);
$p1x_plus_fee = $p1x * (1 + $token_fee);
$amounts.x = floor(($p2_minus_fee - $p1x_plus_fee)/$p2_minus_fee / (1/$denom2 + 1/$denom1));
$amounts.y = floor($amounts.x * $p2_minus_fee); // overestimate
$scale_amounts_down_if_necessary($amounts, $x_balance, $y_balance);
$final_pyx = 1/$p2 * (1 + $amounts.x/($denom2 + $beta * $Lambda * $amounts.x) * $share);
// log({p1: $p1, p2: $p2, p1_plus_fee: $p1_plus_fee, p2_minus_fee: $p2_minus_fee, final_pyx: $final_pyx, denom2: $denom2, amounts: $amounts});
if ($amounts.x <= $x_balance){
$from = 'v2x';
$asset = $x_asset;
$amount = $amounts.x;
$address = $v2_aa;
$data = {
final_price: $final_pyx,
hops: [
{ // next oswap in the chain
address: $token_aa,
change_address: this_address,
data: {to: this_address},
},
]
};
}
else {
$from = 'tokeny';
$asset = $y_asset;
$amount = $amounts.y;
$address = $token_aa;
$data = {
hops: [
{
address: $v2_aa,
data: {
final_price: $final_pyx,
}
},
{
address: this_address
}
]
};
}
}
else
bounce("no arb opportunity exists");
}
else { // overridden in the request, don't calc
$amount = trigger.data.amount;
$from = trigger.data.from;
if ($from == 'v2y'){
$asset = $y_asset;
$address = $v2_aa;
$data = {
final_price: trigger.data.final_p,
hops: [
{ // next oswap in the chain
address: $token_aa,
change_address: this_address,
data: {to: this_address},
},
]
};
}
else if ($from == 'tokenx'){
$asset = $x_asset;
$address = $token_aa;
$data = {
hops: [
{
address: $v2_aa,
data: {
final_price: trigger.data.final_p,
}
},
{
address: this_address
}
]
};
}
else if ($from == 'v2x'){
$asset = $x_asset;
$address = $v2_aa;
$data = {
final_price: trigger.data.final_pyx,
hops: [
{ // next oswap in the chain
address: $token_aa,
change_address: this_address,
data: {to: this_address},
},
]
};
}
else if ($from == 'tokeny'){
$asset = $y_asset;
$address = $token_aa;
$data = {
hops: [
{
address: $v2_aa,
data: {
final_price: trigger.data.final_pyx,
}
},
{
address: this_address
}
]
};
}
}
}",
"messages": [
{
"app": "payment",
"payload": {
"asset": "{$asset}",
"outputs": [
{
"address": "{$address}",
"amount": "{ $amount }"
}
]
}
},
{
"app": "data",
"payload": "{$data}"
},
{
"app": "state",
"state": "{
$arb = {
from: $from,
avg_price: ($p1x + $p2) / 2,
sent: {},
received: {},
};
$arb.sent[$asset] = $amount;
var['arb'] = $arb;
// log({arb: $arb});
response['sent_amount'] = $amount;
if ($from == 'v2y')
response['message'] = 'will arb by buying X from v2 and selling to token';
else if ($from == 'tokenx')
response['message'] = 'will arb by selling X to token and buying from v2';
else if ($from == 'v2x')
response['message'] = 'will arb by selling X to v2 and buying from token';
else if ($from == 'tokeny')
response['message'] = 'will arb by buying X from token and selling to v2';
}"
}
]
},
{
"if": "{
$received_x = trigger.output[[asset=$x_asset]];
$received_y = trigger.output[[asset=$y_asset]];
$arb = var['arb'];
($received_x > 0 OR $received_y > 0) AND (trigger.address == $token_aa OR trigger.address == $v2_aa) AND $arb
}",
"init": "{
$from_token = $arb.from == 'tokenx' OR $arb.from == 'tokeny';
require(!($from_token AND trigger.address == $token_aa), 'change from token AA?');
}",
"messages": [
{
"app": "state",
"state": "{
$arb.received[$x_asset] = $arb.received[$x_asset] + $received_x;
$arb.received[$y_asset] = $arb.received[$y_asset] + $received_y;
$change = !$from_token AND trigger.address == $v2_aa;
if ($change){
var['arb'] = $arb;
response['message'] = 'received the change from v2';
// log('received the change from v2', $received_x, $received_y);
return;
}
// log('received proceeds', $received_x, $received_y);
$sent = $arb.sent[$y_asset] + $arb.sent[$x_asset] * $arb.avg_price;
$received = $arb.received[$y_asset] + $arb.received[$x_asset] * $arb.avg_price;
$profit_in_y = $received - $sent;
$profit_in_x = $profit_in_y / $arb.avg_price;
$profit = $reversed ? $profit_in_x : $profit_in_y; // in GBYTE
require($profit > 0, "unprofitable " || $arb.from || ": " || $received || " < " || $sent);
response['profit'] = $profit; // in GBYTE
var['arb'] = false;
}"
}
]
},
{
"if": "{ trigger.data.withdraw AND trigger.data.asset AND trigger.address == params.owner }",
"init": "{
if (trigger.data.asset == 'x')
$asset = $x_asset;
else if (trigger.data.asset == 'y')
$asset = $y_asset;
else
$asset = trigger.data.asset;
}",
"messages": [
{
"app": "payment",
"payload": {
"asset": "{$asset}",
"outputs": [
{
"address": "{params.owner}",
"amount": "{ trigger.data.amount OTHERWISE '' }"
}
]
}
}
]
},
{
"if": "{ trigger.output[[asset=$x_asset]] > 0 OR trigger.output[[asset=$y_asset]] > 0 }",
"messages": [
{
"app": "state",
"state": "{
response['message'] = 'added';
}"
}
]
}
]
}
}
]