Definition: [
"autonomous agent",
{
"getters": "{
$get_leverages = () => [2, 5, 10, 20, 50, 100];
$singularity_threshold = 0.1;
$get_utilization_ratio = ($balances, $l_balances, $x0, $y0, $alpha) => {
$beta = 1 - $alpha;
$ratio = reduce($get_leverages(), 6, ($acc, $L) => $acc + $l_balances[$L||'x'].balance/($balances.x+$x0)*($L-1)/$beta + $l_balances[-$L||'x'].balance/($balances.y+$y0)*($L-1)/$alpha, 0);
$ratio
};
// X through Y:
// without LP leverage (Lambda)
$get_final_x = ($X, $Y, $final_Y, $X0, $Y0, $pool_props, $inverted) => {
require($final_Y >= $Y, "not selling Y");
$a = $inverted ? $pool_props.beta : $pool_props.alpha; // alpha
$b = 1 - $a; // beta
$final_X = ($X + $X0) * (($Y + $Y0)/($final_Y + $Y0))^($b/$a) - $X0;
require($final_X >= 0, "bad final_X " || $final_X);
$deltaX = $X - $final_X;
require($deltaX >= 0, "bad deltaX " || $deltaX);
round($final_X)
};
// along x means keeping x fully leveraged (y underleveraged)
$get_final_x_along_x = ($X, $Y, $final_Y, $pool_props, $inverted) => {
$b = $inverted ? $pool_props.alpha : $pool_props.beta; // beta
round($X * ($final_Y/$Y)^($b * $pool_props.Lambda/($b * $pool_props.Lambda - 1)))
};
// along y means keeping y fully leveraged (x underleveraged)
$get_final_x_along_y = ($X, $Y, $final_Y, $pool_props, $inverted) => {
$a = $inverted ? $pool_props.beta : $pool_props.alpha; // alpha
round($X * ($final_Y/$Y)^(1-1/$a/$pool_props.Lambda))
};
// Y through X:
// without LP leverage (Lambda)
$get_final_y = ($X, $Y, $final_X, $X0, $Y0, $pool_props, $inverted) => {
// require($final_X <= $X, "not buying X");
$a = $inverted ? $pool_props.beta : $pool_props.alpha; // alpha
$b = 1 - $a; // beta
$final_Y = ($Y + $Y0) * (($X + $X0)/($final_X + $X0))^($a/$b) - $Y0;
require($final_Y >= 0, "bad final_Y " || $final_Y);
$deltaY = $final_Y - $Y;
// require($deltaY >= 0, "bad deltaY " || $deltaY);
round($final_Y)
};
// along x means keeping x fully leveraged (y underleveraged)
$get_final_y_along_x = ($X, $Y, $final_X, $pool_props, $inverted) => {
$b = $inverted ? $pool_props.alpha : $pool_props.beta; // beta
round($Y * ($final_X/$X)^(1 - 1/$b/$pool_props.Lambda))
};
// along y means keeping y fully leveraged (x underleveraged)
$get_final_y_along_y = ($X, $Y, $final_X, $pool_props, $inverted) => {
$a = $inverted ? $pool_props.beta : $pool_props.alpha; // alpha
round($Y * ($final_X/$X)^($a*$pool_props.Lambda/($a*$pool_props.Lambda - 1)))
};
$add_net_balance_without_changing_price = ($balances, $side, $amount, $Lambda) => {
require($Lambda > 1, "Lambda must be > 1");
$opposite = $side == 'x' ? 'y' : 'x';
$side_n = $side || 'n';
$opposite_n = $opposite || 'n';
$Xn = $balances[$side_n];
$Yn = $balances[$opposite_n];
$X = $balances[$side];
$Y = $balances[$opposite];
$underleveraged = $Xn > ceil($X/$Lambda);
$delta_Xn = $amount;
// $delta_Yn = 0;
// the price doesn't change as X and Y grow proportionally
if (!$underleveraged){
// Y is underleveraged, increase Y proportionally while keeping Yn intact
$full_delta_Y = $Y * $delta_Xn/$Xn;
if ($Y + $full_delta_Y > $Yn * $Lambda){ // would overshoot and make Y overleveraged
$ratio = $Yn * $Lambda / $Y - 1;
$delta_X = round($ratio * $X);
$delta_Y = round($ratio * $Y);
}
else{
$delta_X = round($delta_Xn * $Lambda);
$delta_Y = round($full_delta_Y);
}
}
else{
$delta_X = 0; // only net X gets increased
$delta_Y = 0;
}
$balances[$side_n] = $balances[$side_n] + $delta_Xn;
// $balances[$opposite_n] = $balances[$opposite_n] + $delta_Yn;
$balances[$side] = $balances[$side] + $delta_X;
$balances[$opposite] = $balances[$opposite] + $delta_Y;
};
$charge_interest = ($balances, $l_balances, $profits, $x0, $y0, $last_ts, $i, $alpha, $Lambda) => {
require($last_ts, "no last ts");
$beta = 1 - $alpha;
$x = $balances.x;
$y = $balances.y;
$accrued_rate = (timestamp - $last_ts)/3600/24/360 * $i;
if ($Lambda == -1){
$sumX = reduce($get_leverages(), 6, ($acc, $L) => $acc + ($L-1)*$l_balances[$L||'x'].balance, 0) / ($x + $x0);
$sumY = reduce($get_leverages(), 6, ($acc, $L) => $acc + ($L-1)*$l_balances[-$L||'x'].balance, 0) / ($y + $y0);
}
else{ // we change x and y in such a way that the price does not change
$sumX = 0;
$sumY = 0;
}
$denom = 1 - $sumX - $sumY;
$y2x = ($y + $y0) / ($x + $x0);
$p = $alpha/$beta * $y2x;
$n_deltas = {dxn:0, dyn:0};
$sums = {x:0, y:0, xd:0, yd:0};
foreach($get_leverages(), 6, ($L) => {
$xL = $l_balances[$L||'x'].balance;
$yL = $l_balances[-$L||'x'].balance;
if ($xL){
$dxL = -min(round($xL * ($L-1) * $accrued_rate * (1 - 2 * $sumY) / $denom), $xL);
$l_balances[$L||'x'].balance = $xL + $dxL;
$sums.x = $sums.x + $dxL;
$sums.xd = $sums.xd + $dxL * ($L-1)/$L;
// $n_deltas.dxn = $n_deltas.dxn - $dxL;
// $dxL * $p comes from swapping, minus the pool's earnings from interest $dxL * $p / $L
// change in the amount lent out by the swap pool (swap pool's assets)
$delta_yn = $dxL * $p * ($L-1)/$L; // < 0
$n_deltas.dyn = $n_deltas.dyn + $delta_yn;
if ($Lambda == 1){
$n_deltas.dxn = $n_deltas.dxn + $delta_yn / $y2x; // proportional - no price change
// $profits.y = $profits.y - $dxL * $p / $L;
$profits.x = $profits.x - $dxL - $delta_yn / $y2x;
}
else
$n_deltas.dxn = -$dxL; // > 0
}
if ($yL){
$dyL = -min(round($yL * ($L-1) * $accrued_rate * (1 - 2 * $sumX) / $denom), $yL);
$l_balances[-$L||'x'].balance = $yL + $dyL;
$sums.y = $sums.y + $dyL;
$sums.yd = $sums.yd + $dyL * ($L-1)/$L;
// $n_deltas.dyn = $n_deltas.dyn - $dyL;
// $dyL / $p comes from swapping, minus the pool's earnings from interest $dyL / $p / $L
// change in the amount lent out by the swap pool (swap pool's assets)
$delta_xn = $dyL / $p * ($L-1)/$L; // < 0
$n_deltas.dxn = $n_deltas.dxn + $delta_xn;
if ($Lambda == 1){
$n_deltas.dyn = $n_deltas.dyn + $delta_xn * $y2x; // proportional - no price change
// $profits.x = $profits.x - $dyL / $p / $L;
$profits.y = $profits.y - $dyL - $delta_xn * $y2x;
}
else
$n_deltas.dyn = -$dyL; // > 0
}
});
// log('interest', $n_deltas);
// $p = ($alpha * ($y + $y0) - $alpha * $sums.y - $beta * $sums.yd) / ($beta * ($x + $x0) - $beta * $sums.x - $alpha * $sums.xd);
// $dxn = -$sums.x + $sums.yd / $p;
// $dyn = -$sums.y + $sums.xd * $p;
$dxn = round($n_deltas.dxn);
$dyn = round($n_deltas.dyn);
// $dxn = round($n_deltas.dxn - $n_deltas.dyn / $p);
// $dyn = round($n_deltas.dyn - $n_deltas.dxn * $p);
// require($dyn == round($p * $dxn), "dyn " || $dyn || " != calc " || round($p * $dxn));
if ($Lambda == 1){
$profits.x = round($profits.x);
$profits.y = round($profits.y);
$balances.xn = $balances.xn + $dxn;
$balances.yn = $balances.yn + $dyn;
$balances.x = $balances.x + $dxn;
$balances.y = $balances.y + $dyn;
}
else{
$add_net_balance_without_changing_price($balances, 'x', $dxn, $Lambda);
$add_net_balance_without_changing_price($balances, 'y', $dyn, $Lambda);
}
};
$pow = ($precomputed, $power) => {
require($precomputed[$power], "no precomputed power " || $power);
$precomputed[$power]
};
$precompute = $v => {
$pre = {};
$pre['2'] = $v * $v;
$pre['5'] = $pre['2'] * $pre['2'] * $v;
$pre['10'] = $pre['5'] * $pre['5'];
$pre['20'] = $pre['10'] * $pre['10'];
$pre['50'] = $pre['20'] * $pre['20'] * $pre['10'];
$pre['100'] = $pre['50'] * $pre['50'];
$pre
};
$update_leveraged_balances = ($x, $y, $final_x, $final_y, $x0, $y0, $l_balances, $alpha, $inverted) => {
$beta = 1 - $alpha;
$p = $alpha/$beta * ($y + $y0) / ($x + $x0); // price of x in terms of y
$P = $inverted ? 1/$p : $p; // price of X in terms of Y
$final_p = $alpha/$beta * ($final_y + $y0) / ($final_x + $x0);
$final_P = $inverted ? 1/$final_p : $final_p;
$ratio = $final_P/$P;
$ratio_powers = $precompute($ratio);
$totals = {
delta_XL: 0, // (L>0) X added to the L-pools (bought from the swap pool) minus (L<0) new X borrowed by the L-pools (sent to the swap pool for buying Y)
delta_YL: 0, // (L>0) Y added to the L-pools (bought from the swap pool) minus (L<0) new Y borrowed by the L-pools (sent to the swap pool for buying X)
XL_denom: 0,
YL_denom: 0,
}; // if inverted, XL corresponds to y, YL to x
foreach($get_leverages(), 6, ($L) => {
$allyL = $inverted ? -$L : $L;
$balance = $l_balances[$allyL||'x'].balance;
$obalance = $l_balances[-$allyL||'x'].balance;
if (!$balance AND !$obalance)
return;
$ratio_L1 = $pow($ratio_powers, $L) / $ratio;
$debt_ratio = ($L-1)/$L;
if ($balance) {
$delta_XL_balance = round($balance * ($ratio_L1 - 1));
$new_XL_balance = $balance + $delta_XL_balance;
$l_balances[$allyL||'x'].balance = $new_XL_balance;
$delta_YL_balance = -(($new_XL_balance * $final_P - $balance * $P) * $debt_ratio); // borrowed
$totals.delta_XL = $totals.delta_XL + $delta_XL_balance;
$totals.delta_YL = $totals.delta_YL + $delta_YL_balance;
$totals.XL_denom = $totals.XL_denom + $new_XL_balance * ($L-1);
}
if ($obalance) { // e.g. L=-2
$delta_YL_obalance = round($obalance * (1/$ratio_L1 - 1));
$new_YL_obalance = $obalance + $delta_YL_obalance;
$l_balances[-$allyL||'x'].balance = $new_YL_obalance;
$delta_XL_obalance = -(($new_YL_obalance / $final_P - $obalance / $P) * $debt_ratio); // borrowed
$totals.delta_YL = $totals.delta_YL + $delta_YL_obalance;
$totals.delta_XL = $totals.delta_XL + $delta_XL_obalance;
$totals.YL_denom = $totals.YL_denom + $new_YL_obalance * ($L-1);
}
});
$totals
};
$swap = ($balances, $l_balances, $x0, $y0, $y_in, $delta_Yn, $in_final_P, $received_amount_Y, $min_amount_out, $pool_props) => {
require(!$in_final_P, "no final price please, this is swap by Y");
$alpha = $pool_props.alpha;
$beta = $pool_props.beta;
$Lambda = $pool_props.Lambda;
$xn = $balances.xn;
$yn = $balances.yn;
$x = $balances.x;
$y = $balances.y;
if ($y_in){
$inverted = false;
$X = $x;
$Y = $y;
$Xn = $xn;
$Yn = $yn;
$X0 = $x0;
$Y0 = $y0;
$a = $alpha;
$b = $beta;
}
else{ // x <-> y swap their roles. Uppercase X, Y, and P refer to invertable values
$inverted = true;
$X = $y;
$Y = $x;
$Xn = $yn;
$Yn = $xn;
$X0 = $y0;
$Y0 = $x0;
$a = $beta;
$b = $alpha;
}
require($delta_Yn > 0 AND is_integer($delta_Yn), "bad delta " || $delta_Yn);
if ($Lambda > 1){
$underleveraged = $Xn > ceil($X/$Lambda);
}
$final_Yn = $Yn + $delta_Yn;
if ($Lambda == 1){
$final_Xn = $get_final_x($X, $Y, $final_Yn, $X0, $Y0, $pool_props, $inverted);
$final_X = $final_Xn;
$final_Y = $final_Yn;
}
else if (!$underleveraged){ // along X
$delta_Y = -round(($b*$Lambda-1)/$a*$delta_Yn);
$final_Y = $Y + $delta_Y;
$final_X = $get_final_x_along_x($X, $Y, $final_Y, $pool_props, $inverted);
$final_Xn = round($final_X/$Lambda);
// $leveraged_along = 'X';
}
else if ($underleveraged){
$delta_Yn_inflection = round($Y * (( $Lambda/($Lambda-1) * ($b + ($a * $Lambda - 1) * $Xn/$X) )^($a * $Lambda/($a*$Lambda-1)) - 1) / $Lambda);
$inflected = $delta_Yn > $delta_Yn_inflection;
// along Y until the inflection point
$inflection_Yn = $Yn + $delta_Yn_inflection;
$final_Yn1 = $inflected ? $inflection_Yn : $final_Yn;
$final_Y1 = round($final_Yn1 * $Lambda);
$final_X1 = $get_final_x_along_y($X, $Y, $final_Y1, $pool_props, $inverted);
$delta_X1 = $final_X1 - $X;
$delta_Xn1 = -round($b/($a*$Lambda-1) * $delta_X1);
$final_Xn1 = $Xn + $delta_Xn1;
if ($inflected){
// then, along X
$delta_Yn2 = $final_Yn - $final_Yn1;
$delta_Y2 = -round(($b*$Lambda-1)/$a*$delta_Yn2);
$final_Y = $final_Y1 + $delta_Y2;
$final_X = $get_final_x_along_x($final_X1, $final_Y1, $final_Y, $pool_props, $inverted);
$final_Xn = round($final_X/$Lambda);
require($final_Xn <= $final_Xn1, "Xn didn't decrease");
// $leveraged_along = 'X';
}
else{
$final_X = $final_X1;
$final_Xn = $final_Xn1;
$final_Y = $final_Y1;
// $leveraged_along = 'Y';
}
}
else
bounce("???");
$balances.x = $y_in ? $final_X : $final_Y;
$balances.y = $y_in ? $final_Y : $final_X;
$balances.xn = $y_in ? $final_Xn : $final_Yn;
$balances.yn = $y_in ? $final_Yn : $final_Xn;
$final_y = $balances.y;
$final_x = $balances.x;
// $final_Yn = $res.Yn;
// $final_Xn = $res.Xn;
// $final_X = $res.X;
// $final_Y = $res.Y;
// if inverted, XL corresponds to y, YL to x
$totals = $update_leveraged_balances($x, $y, $final_x, $final_y, $x0, $y0, $l_balances, $alpha, $inverted);
$amount_X = floor(-($final_Xn - $X + $totals.delta_XL));
$amount_Y = ceil($final_Yn - $Yn + $totals.delta_YL);
if ($received_amount_Y >= 0)
require($received_amount_Y >= $amount_Y, "expected " || $amount_Y || ", received " || $received_amount_Y);
require($amount_X >= 0, "to pay " || $amount_X);
if ($min_amount_out)
require($amount_X >= $min_amount_out, "output amount " || $amount_X || " would be less than the expected minimum " || $min_amount_out);
$change = $received_amount_Y - $amount_Y;
$denom = 1 - $totals.XL_denom/$b/($final_X+$X0) - $totals.YL_denom/$a/($final_Y+$Y0);
log('denom after L', $denom);
require($denom >= $singularity_threshold, "too close to the singularity point, denom="||$denom||", need more liquidity in order to swap this amount");
// arb tax based on price difference
$p = $alpha/$beta * ($y + $y0) / ($x + $x0); // price of x in terms of y
$P = $inverted ? 1/$p : $p; // price of X in terms of Y
$final_p = $alpha/$beta * ($final_y + $y0) / ($final_x + $x0);
$final_P = $inverted ? 1/$final_p : $final_p;
require($final_P > $P, "price should have risen but hasn't, old " || $P || ", new " || $final_P);
$arb_profit_in_Y = ($final_P - $P) * $amount_X / 2; // in Y
$arb_profit_in_X = $arb_profit_in_Y / $final_P;
$fee = ceil($arb_profit_in_X * $pool_props.arb_profit_tax + $amount_X * $pool_props.swap_fee);
$net_amount_X = $amount_X - $fee;
// add the fee to the pool without trading and affecting the price (Lambda>1) or to a separate profit accumulator (Lambda=1)
// add the fee to the pool, this might affect the price amd make L-pools trade
if ($Lambda == 1){
// some X has been added to the pool, therefore X got cheaper and L-pools need to trade
// These calculations assume the fee is small compared with the pool size
/* $sumX = reduce($leverages, 6, ($acc, $L) => $acc + ($L-1)*$l_balances[$L].balance, 0) / ($x + $x0);
$sumY = reduce($leverages, 6, ($acc, $L) => $acc + ($L-1)*$l_balances[-$L].balance, 0) / ($y + $y0);
$fee_delta_X_traded = $fee * ($sumX + $beta/$alpha * $sumY) / (1 - $sumX/$beta - $sumY/$alpha);
$fee_delta_Xn = $fee + $fee_delta_X_traded;
$fee_delta_Yn = -$p * $fee_delta_X_traded;
$fee_delta_X = $fee_delta_Xn;
$fee_delta_Y = $fee_delta_Yn;*/
}
else{
$add_net_balance_without_changing_price($balances, $y_in ? 'x' : 'y', $fee, $Lambda);
/* $fee_delta_Xn = $fee;
$fee_delta_Yn = 0;
// the price doesn't change as X and Y grow proportionally
if ($res.leveraged_along == 'X'){
// Y is underleveraged, increase Y proportionally while keeping Yn intact
$full_fee_delta_Y = $final_Y * $fee_delta_Xn/$final_Xn;
if ($final_Y + $full_fee_delta_Y > $final_Yn * $Lambda){ // would overshoot and make Y overleveraged
$ratio = $final_Yn * $Lambda / $final_Y - 1;
$fee_delta_X = round($ratio * $final_X);
$fee_delta_Y = round($ratio * $final_Y);
}
else{
$fee_delta_X = round($fee_delta_Xn * $Lambda);
$fee_delta_Y = round($full_fee_delta_Y);
}
}
else{
$fee_delta_X = 0; // only net X gets increased
$fee_delta_Y = 0;
}*/
}
{
net_amount_X: $net_amount_X,
amount_Y: $amount_Y,
fee: $fee,
change: $change,
// delta_Xn: $final_Xn - $Xn + $fee_delta_Xn,
// delta_Yn: $delta_Yn + $fee_delta_Y,
// delta_X: $final_X - $X + $fee_delta_X,
// delta_Y: $final_Y - $Y + $fee_delta_Y,
}
};
$buy_shares = ($s, $balances, $x0, $y0, $received_amount_x, $received_amount_y, $profits, $pool_props) => {
$Lambda = $pool_props.Lambda;
$alpha = $pool_props.alpha;
$beta = $pool_props.beta;
// $get_shares = ($x_balance, $y_balance) => round($x_balance^$alpha * $y_balance^$beta);
$get_shares = ($x_balance, $y_balance) => round(($x_balance/$y_balance)^$alpha * $y_balance);
$xn = $balances.xn;
$yn = $balances.yn;
$x = $balances.x;
$y = $balances.y;
if (!$s){
require($received_amount_x > 0 AND $received_amount_y > 0, "send both assets for the first issue");
$mid_price = $pool_props.mid_price;
if ($mid_price){
// first issue must be at mid price
require($received_amount_y == round($mid_price * $received_amount_x), "first issue must be at mid price "||$mid_price);
$gamma = $pool_props.gamma;
$shares_amount = round($received_amount_x * $pool_props.mid_price_beta * $gamma / ($gamma - 1));
}
else{
// first issue determines the price
$shares_amount = $get_shares($received_amount_x, $received_amount_y);
}
$balances.xn = $balances.xn + $received_amount_x;
$balances.yn = $balances.yn + $received_amount_y;
$balances.x = $balances.x + round($received_amount_x * $Lambda);
$balances.y = $balances.y + round($received_amount_y * $Lambda);
return {
shares_amount: $shares_amount,
coef: 1,
change_x: 0,
change_y: 0,
// delta_x: round($received_amount_x * $Lambda),
// delta_y: round($received_amount_x * $Lambda),
};
}
$p = $alpha/$beta * ($y + $y0) / ($x + $x0);
$share_price_in_y = ($yn + $p * $xn) / $s;
$share_price_in_x = ($xn + 1/$p * $yn) / $s;
if ($Lambda > 1){
$proportional_y = round($yn/$xn * $received_amount_x);
if ($received_amount_y > $proportional_y){ // ok if x is underleveraged
$target_xn = ceil($x/$Lambda);
if ($xn > $target_xn){ // x is underleveraged
$max_delta_yn = round(($xn/$target_xn-1)*$yn);
$delta_yn1 = min($max_delta_yn, $received_amount_y);
$shares1 = floor($delta_yn1/$share_price_in_y);
}
$delta_xn1 = 0;
}
else{ // received x >= proportional x
$target_yn = ceil($y/$Lambda);
if ($yn > $target_yn){ // y is underleveraged
$max_delta_xn = round(($yn/$target_yn-1)*$xn);
$delta_xn1 = min($max_delta_xn, $received_amount_x);
$shares1 = floor($delta_xn1/$share_price_in_x);
}
$delta_yn1 = 0;
}
$balances.xn = $balances.xn + $delta_xn1;
$balances.yn = $balances.yn + $delta_yn1;
}
else{
$delta_xn1 = 0;
$delta_yn1 = 0;
$shares1 = 0;
}
$remaining = {
x: $received_amount_x - $delta_xn1,
y: $received_amount_y - $delta_yn1,
};
// $y_to_x = ($yn+$delta_yn1)/($xn+$delta_xn1);
$y_to_x = $balances.yn/$balances.xn;
if ($profits.x OR $profits.y){
require($Lambda == 1, "have profits while Lambda is " || $Lambda);
// move proportional amounts of profit from both x and y. The shares to be issued for the moved profit belong to the pool and will not be actually issued
$profits_proportional_y = round($y_to_x * $profits.x);
if ($profits.y > $profits_proportional_y){
$delta_profit_x = $profits.x;
$delta_profit_y = $profits_proportional_y;
$symmetric_moved_profit_shares = $delta_profit_x/$xn * $s;
}
else{
$profits_proportional_x = round($profits.y / $y_to_x);
require($profits_proportional_x <= $profits.x, "profits x " || $profits.x || ", proportional " || $profits_proportional_x);
$delta_profit_x = $profits_proportional_x;
$delta_profit_y = $profits.y;
$symmetric_moved_profit_shares = $delta_profit_y/$yn * $s;
}
$profits.x = $profits.x - $delta_profit_x;
$profits.y = $profits.y - $delta_profit_y;
$balances.xn = $balances.xn + $delta_profit_x;
$balances.yn = $balances.yn + $delta_profit_y;
$balances.x = $balances.x + $delta_profit_x;
$balances.y = $balances.y + $delta_profit_y;
log('after proportional profits: delta_profit_x', $delta_profit_x, 'delta_profit_y', $delta_profit_y, 'remaining profits', $profits, 'symmetric_moved_profit_shares', $symmetric_moved_profit_shares);
// calc the shares to be issued for moving the one-sided profits to the pool, these shares belong to the pool and will not be actually issued
$moved_profit_x = min($profits.x, round($remaining.y / $y_to_x));
$moved_profit_y = min($profits.y, round($remaining.x * $y_to_x));
// $share_price_in_x = ($balances.xn + $profits.x + 1/$p * ($balances.yn + $profits.y)) / $s;
// $share_price_in_y = (($balances.xn + $profits.x) * $p + $balances.yn + $profits.y) / $s;
// $share_price_in_x = ($balances.xn + 1/$p * $balances.yn) / $s; // not including the profits: the profit pool just buys shares along with the user at the old price
// $share_price_in_y = ($balances.xn * $p + $balances.yn) / $s;
$moved_profit_shares = $moved_profit_x/$share_price_in_x + $moved_profit_y/$share_price_in_y + $symmetric_moved_profit_shares;
log('share_price_in_x', $share_price_in_x, 'share_price_in_y', $share_price_in_y, 'moved_profit_shares', $moved_profit_shares, 'moved_profit_x', $moved_profit_x, 'moved_profit_y', $moved_profit_y);
$profits.x = $profits.x - $moved_profit_x;
$profits.y = $profits.y - $moved_profit_y;
$remaining.x = $remaining.x + $moved_profit_x;
$remaining.y = $remaining.y + $moved_profit_y;
// $balances.xn = $balances.xn + $moved_profit_x;
// $balances.yn = $balances.yn + $moved_profit_y;
// $balances.x = $balances.x + $moved_profit_x;
// $balances.y = $balances.y + $moved_profit_y;
}
// part 2: proportional buying
log('before proportional buying: remaining', $remaining, 'y_to_x', $y_to_x);
$remaining_proportional_y = round($y_to_x * $remaining.x);
if ($remaining.y > $remaining_proportional_y){ // excessive y
$proportional_delta_xn = $remaining.x;
$proportional_delta_yn = $remaining_proportional_y;
$change_x = 0;
$change_y = $remaining.y - $remaining_proportional_y;
// $shares_proportional = floor($remaining.x / ($xn + $delta_xn1) * ($s + $shares1));
$shares_proportional = ($remaining.x / $xn * $s);
}
else{ // excessive x
$remaining_proportional_x = round($remaining.y / $y_to_x);
$proportional_delta_xn = $remaining_proportional_x;
$proportional_delta_yn = $remaining.y;
$change_x = $remaining.x - $remaining_proportional_x;
log({proportional_delta_xn:$proportional_delta_xn, change_x:$change_x, remaining_x:$remaining.x, remaining_proportional_x:$remaining_proportional_x});
require($change_x >= 0, "received x " || $remaining.x || ", proportional " || $remaining_proportional_x);
$change_y = 0;
// $shares_proportional = floor($remaining.y / ($yn + $delta_yn1) * ($s + $shares1));
$shares_proportional = ($remaining.y / $yn * $s);
}
$gross_shares_amount = $shares1 + $symmetric_moved_profit_shares + $shares_proportional;
$shares_amount = floor($gross_shares_amount - $moved_profit_shares);
$coef = ($s + $gross_shares_amount) / ($s + $shares_amount);
log({shares_proportional:$shares_proportional, moved_profit_shares:$moved_profit_shares, shares_amount:$shares_amount});
$balances.xn = $balances.xn + $proportional_delta_xn;
$balances.yn = $balances.yn + $proportional_delta_yn;
$balances.x = $balances.x + round($proportional_delta_xn * $Lambda);
$balances.y = $balances.y + round($proportional_delta_yn * $Lambda);
// $balances.x = $balances.x + round(($delta_xn1 + $proportional_delta_xn) * $Lambda);
// $balances.y = $balances.y + round(($delta_yn1 + $proportional_delta_yn) * $Lambda);
{
shares_amount: $shares_amount,
coef: $coef,
change_x: $change_x,
change_y: $change_y,
// delta_x: ($delta_xn1 + $remaining.x - $change_x) * $Lambda,
// delta_y: ($delta_yn1 + $remaining.y - $change_y) * $Lambda,
}
};
$redeem_shares = ($s, $balances, $l_balances, $x0, $y0, $received_shares_amount, $asset, $pool_props) => {
$xn = $balances.xn;
$yn = $balances.yn;
$x = $balances.x;
$y = $balances.y;
$net_of_exit_fee = 1 - $pool_props.exit_fee;
$x_asset = $pool_props.x_asset;
$y_asset = $pool_props.y_asset;
$Lambda = $pool_props.Lambda;
$alpha = $pool_props.alpha;
$beta = $pool_props.beta;
if ($asset){ // one-sided redemption first, then proportional
require($asset == $x_asset OR $asset == $y_asset, "wrong preferred asset");
require($Lambda > 1, "only proportional withdrawals");
$asset_label = $asset == $x_asset ? 'x' : 'y';
$net_balance = $asset == $x_asset ? $xn : $yn;
$effective_balance = $asset == $x_asset ? $x : $y;
$target_net_balance = ceil($effective_balance / $Lambda);
// require($target_net_balance < $net_balance, "the preferred asset is already fully leveraged");
$excess_net_balance = $net_balance - $target_net_balance;
$p = $alpha/$beta * $y / $x;
$share_price_in_asset = ($asset_label == 'y') ? ($yn + $p * $xn) / $s : ($xn + 1/$p * $yn) / $s;
$max_asset = ceil($received_shares_amount * $share_price_in_asset);
$one_sided_amount = min($max_asset, $excess_net_balance);
if ($asset_label == 'y'){
$yn_amount1 = $one_sided_amount;
$xn_amount1 = 0;
}
else{
$xn_amount1 = $one_sided_amount;
$yn_amount1 = 0;
}
$remaining_received_shares = max($received_shares_amount - ceil($excess_net_balance / $share_price_in_asset), 0);
}
else{
$remaining_received_shares = $received_shares_amount;
$xn_amount1 = 0;
$yn_amount1 = 0;
}
$share_of_shares = $remaining_received_shares / $s;
$remaining_share_of_shares = 1 - $share_of_shares;
$remaining_share_of_assets = $remaining_share_of_shares;
$share_of_assets = 1 - $remaining_share_of_assets;
$x_amount = floor($share_of_assets * $x * $net_of_exit_fee);
$y_amount = floor($share_of_assets * $y * $net_of_exit_fee);
$xn_amount = floor(($share_of_assets * ($xn - $xn_amount1) + $xn_amount1) * $net_of_exit_fee);
$yn_amount = floor(($share_of_assets * ($yn - $yn_amount1) + $yn_amount1) * $net_of_exit_fee);
$balances.x = $balances.x - $x_amount;
$balances.y = $balances.y - $y_amount;
$balances.xn = $balances.xn - $xn_amount;
$balances.yn = $balances.yn - $yn_amount;
$new_x0 = $x0 * ($s-$received_shares_amount)/$s;
$new_y0 = $y0 * ($s-$received_shares_amount)/$s;
$denom = 1 - $get_utilization_ratio($balances, $l_balances, $new_x0, $new_y0, $alpha);
require($denom >= $singularity_threshold, "redemption amount too large, it would bring us too close to the singularity point, denom="||$denom);
{
xn_amount: $xn_amount,
yn_amount: $yn_amount,
x_amount: $x_amount,
y_amount: $y_amount,
}
};
$update_other_l_balances_and_get_sums = ($l_balances, $P, $final_P, $Leverage, $inverted) => {
// $P_powers = $precompute($P);
// $final_P_powers = $precompute($final_P);
$ratio = $final_P/$P;
$ratio_powers = $precompute($ratio);
$sums = {
initial: 0,
final: 0,
delta_XL: 0,
XL_denom: 0,
YL_denom: 0,
PL1_ratio: $pow($ratio_powers, $Leverage) / $ratio,
};
foreach($get_leverages(), 6, $L => {
$allyL = $inverted ? -$L : $L;
$balance = $l_balances[$allyL||'x'].balance;
$obalance = $l_balances[-$allyL||'x'].balance;
if (!$balance AND !$obalance)
return;
// $PL1 = $pow($P_powers, $L) / $P;
// $final_PL1 = $pow($final_P_powers, $L) / $final_P;
$ratio_L1 = $pow($ratio_powers, $L) / $ratio;
if ($balance){
$sums.initial = $sums.initial + $balance * ($L-1)/$L;
if ($L != $Leverage){
$new_balance = ($balance * $ratio_L1);
// $new_balance = round($balance * $ratio_L1);
$l_balances[$allyL||'x'].balance = $new_balance;
$sums.final = $sums.final + $new_balance * ($L-1)/$L;
$sums.XL_denom = $sums.XL_denom + $new_balance * ($L-1);
$sums.delta_XL = $sums.delta_XL + $new_balance - $balance;
}
}
if ($obalance){
$sums.initial = $sums.initial - $obalance/$P;
$new_obalance = ($obalance / $ratio_L1);
// $new_obalance = round($obalance / $ratio_L1);
$l_balances[-$allyL||'x'].balance = $new_obalance;
$sums.final = $sums.final - $new_obalance/$final_P;
$sums.YL_denom = $sums.YL_denom + $new_obalance * ($L-1);
$sums.delta_XL = $sums.delta_XL - ($new_obalance / $final_P - $obalance / $P) * ($L-1)/$L; // delta of the swap-pool's X: borrowed X changes by trading in the pool
}
});
// $sums.delta_XL = round($sums.delta_XL);
$sums
};
// delta_Xn < 0: buy L-tokens
// delta_Xn > 0: sell L-tokens
$trade_l_shares = ($balances, $l_balances, $x0, $y0, $Leverage, $asset, $delta_Xn, $entry_price, $pool_props) => {
require(is_integer($delta_Xn), "delta must be int");
require($asset == $pool_props.x_asset OR $asset == $pool_props.y_asset, "wrong asset");
require($Leverage == 2 OR $Leverage == 5 OR $Leverage == 10 OR $Leverage == 20 OR $Leverage == 50 OR $Leverage == 100, "bad L");
$Lambda = $pool_props.Lambda;
if ($asset == $pool_props.x_asset){
$inverted = false;
$X = $balances.x;
$Y = $balances.y;
$Xn = $balances.xn;
$Yn = $balances.yn;
$X0 = $x0;
$Y0 = $y0;
$a = $pool_props.alpha;
$b = $pool_props.beta;
}
else{ // x <-> y swap their roles. Uppercase X, Y, and P refer to invertable values
$inverted = true;
$X = $balances.y;
$Y = $balances.x;
$Xn = $balances.yn;
$Yn = $balances.xn;
$X0 = $y0;
$Y0 = $x0;
$a = $pool_props.beta;
$b = $pool_props.alpha;
}
require($Xn + $delta_Xn > 0, "Xn balance would be negative");
$L_key = ($inverted ? -$Leverage : $Leverage) || 'x';
$l_bal_direction = $delta_Xn < 0 ? "grow" : "fall";
$pool = {X: $X, Y: $Y, Xn: $Xn, Yn: $Yn, XL: 0};
$move_unleveraged = ($dXn) => {
$Xt = $pool.X + $X0;
$P = $a/$b * ($pool.Y + $Y0) / $Xt;
$final_Xn = $pool.Xn + $dXn;
$final_X = $final_Xn;
$final_Xt = $final_X + $X0;
$final_Y = $get_final_y($pool.X, $pool.Y, $final_X, $X0, $Y0, $pool_props, $inverted);
$delta_Y = $final_Y - $pool.Y;
$delta_Yn = $delta_Y;
$final_Yn = $pool.Yn + $delta_Yn;
$final_P = $a/$b * ($final_Y + $Y0) / $final_Xt;
log('l balances before', $l_balances);
$sums = this_address#1.$update_other_l_balances_and_get_sums($l_balances, $P, $final_P, $Leverage, $inverted);
log('sums', $sums);
log('l balances after', $l_balances);
// update the final balance of our L-pool
$b1 = $sums.initial + $b/($b-1)*$Xt;
$new_l_balance = ( $Leverage/($Leverage-1) * ( -$sums.final - $b/($b-1)*$final_Xt + $b1 * ($final_Xt/$Xt)^(1/$b) ) );
// $new_l_balance = round( $Leverage/($Leverage-1) * ( -$sums.final - $b/($b-1)*$final_Xt + $b1 * ($final_Xt/$Xt)^(1/$b) ) );
log('new_l_balance', $new_l_balance);
$delta_l_balance = $new_l_balance - $l_balances[$L_key].balance;
log('delta_l_balance', $delta_l_balance);
require($delta_l_balance * $delta_Xn < 0, "unleveraged l-bal should "||$l_bal_direction||", got new " || $new_l_balance || ", delta " || $delta_l_balance);
$l_balances[$L_key].balance = $new_l_balance;
log('l balances after 2', $l_balances);
$pool.X = $final_X;
$pool.Y = $final_Y;
$pool.Xn = $final_Xn;
$pool.Yn = $final_Yn;
$pool.delta_XL = $pool.delta_XL + $sums.delta_XL;
$pool.XL_denom = $sums.XL_denom + $new_l_balance * ($Leverage-1);
$pool.YL_denom = $sums.YL_denom;
$pool.PL1_ratio = $sums.PL1_ratio;
};
$move_along_X = ($dXn) => {
$P = $a/$b * ($pool.Y + $Y0) / ($pool.X + $X0);
$final_Xn = $pool.Xn + $dXn;
$final_X = $Lambda * $final_Xn;
$final_Y = $get_final_y_along_x($pool.X, $pool.Y, $final_X, $pool_props, $inverted);
$delta_Y = $final_Y - $pool.Y;
$delta_Yn = -round($a/($b*$Lambda-1)*$delta_Y);
$final_Yn = $pool.Yn + $delta_Yn;
$final_P = $a/$b * ($final_Y + $Y0) / ($final_X + $X0);
$sums = this_address#1.$update_other_l_balances_and_get_sums($l_balances, $P, $final_P, $Leverage, $inverted);
// update the final balance of our L-pool
$b1 = $sums.initial + $b/($b*$Lambda-1)*$pool.X;
$new_l_balance = round( $Leverage/($Leverage-1) * ( -$sums.final - $b/($b*$Lambda-1)*$final_X + $b1 * ($final_X/$pool.X)^(1/$b/$Lambda) ) );
$delta_l_balance = $new_l_balance - $l_balances[$L_key].balance;
require($delta_l_balance * $delta_Xn < 0, "along x l-bal should "||$l_bal_direction||", got new " || $new_l_balance || ", delta " || $delta_l_balance);
$l_balances[$L_key].balance = $new_l_balance;
$pool.X = $final_X;
$pool.Y = $final_Y;
$pool.Xn = $final_Xn;
$pool.Yn = $final_Yn;
$pool.delta_XL = $pool.delta_XL + $sums.delta_XL;
$pool.XL_denom = $sums.XL_denom + $new_l_balance * ($Leverage-1);
$pool.YL_denom = $sums.YL_denom;
$pool.PL1_ratio = $sums.PL1_ratio;
};
$move_along_Y = ($dXn) => {
$P = $a/$b * ($pool.Y + $Y0) / ($pool.X + $X0);
$final_Xn = $pool.Xn + $dXn;
$delta_X = -round(($a*$Lambda-1)/$b * $dXn);
$final_X = $pool.X + $delta_X;
$final_Y = $get_final_y_along_y($pool.X, $pool.Y, $final_X, $pool_props, $inverted);
$final_Yn = round($final_Y/$Lambda);
$final_P = $a/$b * ($final_Y + $Y0) / ($final_X + $X0);
$sums = this_address#1.$update_other_l_balances_and_get_sums($l_balances, $P, $final_P, $Leverage, $inverted);
// update the final balance of our L-pool
$b2 = $sums.initial - $b/$a/$Lambda*$pool.X;
$new_l_balance = round( $Leverage/($Leverage-1) * ( -$sums.final + $b/$a/$Lambda*$final_X + $b2 * ($final_X/$pool.X)^(-1/($a*$Lambda-1)) ) );
$delta_l_balance = $new_l_balance - $l_balances[$L_key].balance;
require($delta_l_balance * $delta_Xn < 0, "along y l-bal should "||$l_bal_direction||", got new " || $new_l_balance || ", delta " || $delta_l_balance);
$l_balances[$L_key].balance = $new_l_balance;
$pool.X = $final_X;
$pool.Y = $final_Y;
$pool.Xn = $final_Xn;
$pool.Yn = $final_Yn;
$pool.delta_XL = $pool.delta_XL + $sums.delta_XL;
$pool.XL_denom = $sums.XL_denom + $new_l_balance * ($Leverage-1);
$pool.YL_denom = $sums.YL_denom;
$pool.PL1_ratio = $sums.PL1_ratio;
};
$initial_l_balance = $l_balances[$L_key].balance;
$initial_shares = $l_balances[$L_key].supply;
require(!$initial_l_balance == !$initial_shares, "l balance "||$initial_l_balance||" while shares "||$initial_shares);
$initial_P = $a/$b * ($pool.Y + $Y0) / ($pool.X + $X0);
if ($Lambda == 1)
$move_unleveraged($delta_Xn);
else {
$underleveraged = $Xn > ceil($X/$Lambda);
if (!$underleveraged){ // along X
if ($delta_Xn > 0){ // selling L-shares and X
$delta_Xn_inflection = round($X * (( $Lambda/($Lambda-1) * ($a + ($b * $Lambda - 1) * $Yn/$Y) )^($b * $Lambda/($b*$Lambda-1)) - 1) / $Lambda);
$inflected = $delta_Xn > $delta_Xn_inflection;
}
$dXn1 = $inflected ? $delta_Xn_inflection : $delta_Xn;
$move_along_X($dXn1);
if ($inflected)
$move_along_Y($delta_Xn - $delta_Xn_inflection);
}
else{ // along Y
if ($delta_Xn < 0){ // buying L-shares and X
$delta_Xn_inflection = -round($b/($Lambda-1) * ($Lambda*$Xn - $X));
$inflected = abs($delta_Xn) > abs($delta_Xn_inflection);
}
$dXn1 = $inflected ? $delta_Xn_inflection : $delta_Xn;
$move_along_Y($dXn1);
if ($inflected)
$move_along_X($delta_Xn - $delta_Xn_inflection);
}
}
$final_l_balance = $l_balances[$L_key].balance;
$delta_l_balance = $final_l_balance - $initial_l_balance;
// the change in the total X balance of swap pool + all L-pools (positive when buying, negative when selling)
$net_delta = round($delta_Xn + $pool.delta_XL + $delta_l_balance);
$final_shares = $initial_l_balance
? round($final_l_balance/$initial_l_balance / $pool.PL1_ratio * $initial_shares)
: $net_delta; // the initial units for shares are arbitrary
$shares = $final_shares - $initial_shares;
$l_balances[$L_key].supply = $final_shares;
$avg_share_price = $net_delta/$shares;
$denom = 1 - $pool.XL_denom/$b/($pool.X+$X0) - $pool.YL_denom/$a/($pool.Y+$Y0);
log('denom after L', $denom);
require($denom >= $singularity_threshold, "too close to the singularity point, denom="||$denom||", need more liquidity in order to buy this amount of L-tokens");
$balances.x = $inverted ? $pool.Y : $pool.X;
$balances.y = $inverted ? $pool.X : $pool.Y;
$balances.xn = $inverted ? $pool.Yn : $pool.Xn;
$balances.yn = $inverted ? $pool.Xn : $pool.Yn;
// regular trading fee (%) and arb tax are paid on top
$final_P = $a/$b * ($pool.Y + $Y0) / ($pool.X + $X0);
$arb_profit_in_Y = ($final_P - $initial_P) * $net_delta / 2; // in Y
require($arb_profit_in_Y > 0, "arb profit "||$arb_profit_in_Y);
$arb_profit_in_X = $arb_profit_in_Y / $final_P;
$trading_fee = ceil($arb_profit_in_X * $pool_props.arb_profit_tax + abs($net_delta) * $pool_props.swap_fee);
if ($delta_Xn > 0){ // sell
$gross_asset_out = -$net_delta; // gross means before tax and fees
require($gross_asset_out > 0, "asset out must be positive, got " || $gross_asset_out);
if ($entry_price){
// L>0 profit is accounted for in x tokens (in y tokens for L<0) meaning that only profits from the borrowed part of the L-pool are taxed
$l_tax = max(ceil(($avg_share_price - $entry_price)*(-$shares)*$pool_props.leverage_profit_tax), 0);
}
else
$l_tax = ceil($gross_asset_out * $pool_props.leverage_token_tax);
}
$total_fee = $trading_fee + $l_tax;
if ($Lambda > 1)
$add_net_balance_without_changing_price($balances, $inverted ? 'y' : 'x', $total_fee, $Lambda);
// For buying, the fee is added on top. For selling (net_delta<0), the fees are subtracted
$gross_delta = $net_delta + $total_fee;
{
shares: $shares,
net_delta: $net_delta,
gross_delta: $gross_delta,
avg_share_price: $avg_share_price,
l_tax: $l_tax,
trading_fee: $trading_fee,
total_fee: $total_fee,
// delta_l_balance: $delta_l_balance,
// delta_total_XL: $pool.delta_XL,
}
};
$handle_trade_l_shares_request = ($pool_aa, $balances, $l_balances, $x0, $y0, $trigger_data, $trigger_address, $trigger_outputs, $pool_props) => {
$x_asset = $pool_props.x_asset;
$y_asset = $pool_props.y_asset;
$asset = $trigger_data.asset == 'x' ? $x_asset : ($trigger_data.asset == 'y' ? $y_asset : $trigger_data.asset);
$L = $trigger_data.L;
$buy = $trigger_data.buy;
$sell = $trigger_data.sell;
$delta = $trigger_data.delta;
$received_amount = $trigger_outputs[$asset];
$min_received_amount = $asset == 'base' ? 10000 : 0;
$net_received_amount = $received_amount - $min_received_amount;
require(!($buy AND $sell), "buy or sell?");
require($delta > 0, "delta must be positive");
if ($buy)
require($net_received_amount > 0, "you forgot to pay");
else
require($net_received_amount == 0, "don't send asset");
$delta_Xn = $buy ? -$delta : $delta; // Xn in the pool
$asset_label = $asset == $x_asset ? 'x' : 'y';
$signedL = $asset_label == 'x' ? $L : -$L;
if ($buy AND $trigger_data.tokens OR $sell AND !$trigger_data.position){
$l_shares_asset = var[$pool_aa]['leveraged_asset' || $signedL];
require($l_shares_asset, "please define an asset for the leveraged token first");
}
if ($sell){
if ($trigger_data.position){
$position = var[$pool_aa][$trigger_data.position];
require($position, "no such position");
require($position.owner == $trigger_address, "you are not the owner of this position");
$parts = split($trigger_data.position, '_');
require(+$parts[1] == $signedL, "wrong L");
$shares_in = $position.shares;
}
else{
$shares_in = $trigger_outputs[$l_shares_asset];
require($shares_in > 0, "no leveraged tokens received");
}
}
$res = $trade_l_shares($balances, $l_balances, $x0, $y0, $L, $asset, $delta_Xn, $position.price, $pool_props);
$shares = $res.shares;
$gross_delta = $res.gross_delta;
if ($buy){
$asset_out = $received_amount - $gross_delta; // the change
require($asset_out >= 0, "expected " || $gross_delta || ", received " || $received_amount);
}
else{
$shares_change = $shares_in + $shares; // shares < 0
require($shares_change >= 0, "expected " || (-$shares) || " shares, received " || $shares_in);
$asset_out = -$gross_delta;
}
$res.signedL = $signedL;
$res.asset_label = $asset_label;
$res.asset = $asset;
$res.l_shares_asset = $l_shares_asset;
$res.position = $position;
$res.shares_change = $shares_change;
$res.asset_out = $asset_out;
$res
};
$validate_and_apply_new_governed_param_value = ($name, $value, $balances, $profits, $lp_shares, $pool_props, $locked_governance) => {
$Lambda = $pool_props.Lambda;
$alpha = $pool_props.alpha;
$beta = $pool_props.beta;
$gamma = $pool_props.gamma;
$mid_price = $pool_props.mid_price;
if ($locked_governance)
require(!$locked_governance[$name], "governance is not allowed to change "||$name);
if ($name == 'pool_leverage'){
require(!$profits.x AND !$profits.y, "profits must be added to the pool before changing pool_leverage");
require($alpha != 1/$value, "pool leverage = 1/alpha");
require($beta != 1/$value, "pool leverage = 1/beta");
if ($value > 1){
require(!$mid_price, "price range setting is incompatible with new pool leverage");
$balances.x = round($balances.x * $value/$Lambda);
$balances.y = round($balances.y * $value/$Lambda);
}
else{
$balances.x = $balances.xn;
$balances.y = $balances.yn;
}
// we modified balances
}
else if ($name == 'mid_price' OR $name == 'price_deviation'){
require($value AND $mid_price, $name||" must be nonzero");
require($alpha == 0.5, "equal weights only");
if ($name == 'price_deviation'){
require($value > 1, "price deviation must be > 1");
$new_p0 = $mid_price;
$new_gamma = $value;
}
else{
$new_p0 = $value;
$new_gamma = $gamma;
}
$s_curve = $lp_shares.linear * $lp_shares.coef;
$sqp = sqrt($new_p0);
$b = ($balances.x/$s_curve*$sqp + $balances.y/$s_curve/$sqp)/$new_gamma;
$a = $balances.x*$balances.y/$s_curve/$s_curve;
$lp_shares.coef = $lp_shares.coef / (-$b + sqrt($b*$b - 4*$a*(1/$new_gamma/$new_gamma-1)))*2*$a;
// we modified lp_shares
}
else if ($name == 'alpha'){
require(!$mid_price, "can't change token weights while trading in limited range");
require($value != 1/$Lambda AND 1-$value != 1/$Lambda, "pool leverage = 1/alpha or 1/beta");
// s_coef is unused
// var['s_coef'] *= $balances.xn^$value * $balances.yn^(1-$value) / $s_curve;
// nothing modified
}
};
}",
"messages": [
{
"app": "state",
"state": "{
// $u = $get_utilization_ratio();
// $A = $swap();
// $b = $charge_interest();
// $c = $update_leveraged_balances();
// $d = $trade_l_shares();
$h = $handle_trade_l_shares_request();
// $e = $buy_shares();
// $f = $redeem_shares();
// $g = $validate_and_apply_new_governed_param_value();
// $t = $get_total_balances();
bounce("library only");
}"
}
]
}
]