| 1 | [ |
| 2 | "autonomous agent", |
| 3 | { |
| 4 | "getters": "{ |
| 5 | |
| 6 | $year = 31104000; |
| 7 | |
| 8 | $trade_merge_period = 1; |
| 9 | |
| 10 | |
| 11 | $increase_supply = ($state, $ds) => { |
| 12 | require($ds >= 0, "negative ds "||$ds); |
| 13 | $s = $state.supply; |
| 14 | $s0 = $state.s0; |
| 15 | $new_s = $s + $ds; |
| 16 | $new_s0 = $s0 * $new_s * $new_s / ($s0 * $ds + $s * $s); |
| 17 | $coef_multiplier = $s * $s / $new_s / $new_s; |
| 18 | |
| 19 | $state.supply = $new_s; |
| 20 | $state.s0 = $new_s0; |
| 21 | $state.coef = $state.coef * $coef_multiplier; |
| 22 | }; |
| 23 | |
| 24 | $subtract_grant = ($state, $dr) => { |
| 25 | $r = $state.reserve; |
| 26 | require($dr < $r, "proposal amount exceeds the reserve"); |
| 27 | $s = $state.supply; |
| 28 | $s0 = $state.s0; |
| 29 | |
| 30 | $ro = $dr/$r; |
| 31 | $ro1 = 1 - $ro; |
| 32 | |
| 33 | $new_s0 = 1 / ($ro/$s + $ro1/$s0); |
| 34 | $coef_multiplier = $ro1 * $ro1; |
| 35 | |
| 36 | $state.reserve = $r - $dr; |
| 37 | $state.s0 = $new_s0; |
| 38 | $state.coef = $state.coef * $coef_multiplier; |
| 39 | }; |
| 40 | |
| 41 | $update_total_emissions = ($state, $props) => { |
| 42 | $total_new_emissions = $state.total_normalized_vp |
| 43 | ? (timestamp - $state.last_emissions_ts)/$year * $props.inflation_rate * $state.supply |
| 44 | : 0; |
| 45 | $state.last_emissions_ts = timestamp; |
| 46 | $state.stakers_emissions = $state.stakers_emissions + $props.stakers_share * $total_new_emissions; |
| 47 | $state.lp_emissions = $state.lp_emissions + (1 - $props.stakers_share) * $total_new_emissions; |
| 48 | }; |
| 49 | |
| 50 | $distribute_stakers_emissions = ($state, $user, $props) => { |
| 51 | $update_total_emissions($state, $props); |
| 52 | |
| 53 | $new_emissions_since_prev_visit = $state.stakers_emissions - $user.last_stakers_emissions; |
| 54 | $user.last_stakers_emissions = $state.stakers_emissions; |
| 55 | |
| 56 | if ($user.normalized_vp AND $state.total_normalized_vp){ |
| 57 | $reward = $new_emissions_since_prev_visit * $user.normalized_vp/$state.total_normalized_vp; |
| 58 | $user.reward = $user.reward + $reward; |
| 59 | $increase_supply($state, $reward); |
| 60 | } |
| 61 | }; |
| 62 | |
| 63 | $distribute_lp_emissions = ($state, $lp, $pool, $pool_vps, $total_lp_balance, $props) => { |
| 64 | $update_total_emissions($state, $props); |
| 65 | |
| 66 | if (!$state.total_normalized_vp) |
| 67 | return; |
| 68 | |
| 69 | if (!$pool.blacklisted) { |
| 70 | $pool_share = $pool_vps[$pool.asset_key]/$state.total_normalized_vp; |
| 71 | |
| 72 | $new_total_lp_emissions_since_prev_visit = $state.lp_emissions - $pool.last_lp_emissions; |
| 73 | $pool.last_lp_emissions = $state.lp_emissions; |
| 74 | $pool.received_emissions = $pool.received_emissions + $new_total_lp_emissions_since_prev_visit * $pool_share; |
| 75 | } |
| 76 | |
| 77 | $new_emissions_since_prev_visit = $pool.received_emissions - $lp.last_pool_emissions; |
| 78 | $lp.last_pool_emissions = $pool.received_emissions; |
| 79 | |
| 80 | |
| 81 | if ($lp.balance AND $total_lp_balance){ |
| 82 | $reward = $new_emissions_since_prev_visit * $lp.balance/$total_lp_balance; |
| 83 | $lp.reward = $lp.reward + $reward; |
| 84 | $increase_supply($state, $reward); |
| 85 | } |
| 86 | $lp.last_distribution_ts = timestamp; |
| 87 | }; |
| 88 | |
| 89 | |
| 90 | $distribute_new_vp = ($votes, $pool_vps, $delta_normalized_vp, $percentages) => { |
| 91 | $totals = {total: 0}; |
| 92 | foreach($percentages, 20, ($pool_asset_key, $percentage) => { |
| 93 | require(+substring($pool_asset_key, 1) AND starts_with($pool_asset_key, 'a'), "invalid pool asset key "||$pool_asset_key); |
| 94 | require($percentage > 0, "invalid percentage "||$percentage); |
| 95 | require(exists($pool_vps[$pool_asset_key]), "pool asset key "||$pool_asset_key||" not found in this group"); |
| 96 | $totals.total = $totals.total + $percentage; |
| 97 | $added_vp = $percentage/100 * $delta_normalized_vp; |
| 98 | $votes[$pool_asset_key] = $votes[$pool_asset_key] + $added_vp; |
| 99 | $pool_vps[$pool_asset_key] = $pool_vps[$pool_asset_key] + $added_vp; |
| 100 | }); |
| 101 | require($totals.total == 100, "percentages sum to "||$totals.total); |
| 102 | require(length($votes) <= 30, "max total number of supported pools is 30"); |
| 103 | $pool_vps.total = $pool_vps.total + $delta_normalized_vp; |
| 104 | }; |
| 105 | |
| 106 | |
| 107 | $apply_vote = ($votes, $pool_vps, $group_key1, $group_key2, $group_vps, $changes) => { |
| 108 | $totals = {total: 0, max: 0}; |
| 109 | foreach($changes, 20, ($pool_asset_key, $delta_vp) => { |
| 110 | require(+substring($pool_asset_key, 1) AND starts_with($pool_asset_key, 'a'), "invalid pool asset key "||$pool_asset_key); |
| 111 | $votes[$pool_asset_key] = $votes[$pool_asset_key] + $delta_vp; |
| 112 | $p = $votes[$pool_asset_key]; |
| 113 | require($p >= 0, "would have negative votes for pool_asset_key "||$pool_asset_key); |
| 114 | if ($p == 0) |
| 115 | delete($votes, $pool_asset_key); |
| 116 | $totals.total = $totals.total + $delta_vp; |
| 117 | if (abs($delta_vp) > $totals.max) |
| 118 | $totals.max = abs($delta_vp); |
| 119 | if (exists($pool_vps[$group_key1][$pool_asset_key])) |
| 120 | $group_key = $group_key1; |
| 121 | else if ($group_key2 AND exists($pool_vps[$group_key2][$pool_asset_key])) |
| 122 | $group_key = $group_key2; |
| 123 | else |
| 124 | bounce("pool asset key "||$pool_asset_key||" not found in any of the two groups"); |
| 125 | $pool_vps[$group_key][$pool_asset_key] = $pool_vps[$group_key][$pool_asset_key] + $delta_vp; |
| 126 | $pool_vps[$group_key].total = $pool_vps[$group_key].total + $delta_vp; |
| 127 | $group_vps[$group_key] = $group_vps[$group_key] + $delta_vp; |
| 128 | }); |
| 129 | require(abs($totals.total) < $totals.max * 1e-15, "total votes changed by "||$totals.total); |
| 130 | require(length($votes) <= 30, "max total number of supported pools is 30"); |
| 131 | }; |
| 132 | |
| 133 | $remove_votes = ($votes, $pool_vps) => { |
| 134 | foreach($votes, 30, ($pool_asset_key, $vp) => { |
| 135 | require(exists($pool_vps[$pool_asset_key]), "pool asset key "||$pool_asset_key||" not found in the indicated group"); |
| 136 | $pool_vps[$pool_asset_key] = $pool_vps[$pool_asset_key] - $votes[$pool_asset_key]; |
| 137 | }); |
| 138 | }; |
| 139 | |
| 140 | |
| 141 | |
| 142 | |
| 143 | $pow2 = $x => $x*$x; |
| 144 | |
| 145 | |
| 146 | $get_reserve_by_state = ($s, $state) => $state.coef * $s * $state.s0 / ($state.s0 - $s); |
| 147 | $get_tokens_by_state = ($r, $state) => 1 / (1/$state.s0 + $state.coef/$r); |
| 148 | $get_price_by_state = ($s, $state) => $state.coef * $pow2($state.s0 / ($state.s0 - $s)); |
| 149 | |
| 150 | |
| 151 | $get_appreciation_result = ($state, $appreciation_rate) => { |
| 152 | $elapsed_time = timestamp - $state.last_ts; |
| 153 | |
| 154 | $r = $state.reserve; |
| 155 | $s = $state.supply; |
| 156 | $s0 = $state.s0; |
| 157 | if ($s == 0 OR $elapsed_time == 0) |
| 158 | return {new_s0: $s0, coef_multiplier: 1}; |
| 159 | $p = $get_price_by_state($s, $state); |
| 160 | $new_p = $p * (1 + $elapsed_time/$year * $appreciation_rate); |
| 161 | $new_s0 = $s + 1 / ($new_p/$r - 1/$s); |
| 162 | require($new_s0 > 0, "appreciation new s0 = "||$new_s0); |
| 163 | $coef_multiplier = $s0/$new_s0 * ($new_s0 - $s)/($s0 - $s); |
| 164 | require($coef_multiplier > 0 AND $coef_multiplier <= 1, "invalid appreciation coef multiplier "||$coef_multiplier); |
| 165 | { |
| 166 | new_s0: $new_s0, |
| 167 | coef_multiplier: $coef_multiplier, |
| 168 | } |
| 169 | }; |
| 170 | |
| 171 | $apply_appreciation = ($state, $appreciation_rate) => { |
| 172 | $appr_res = $get_appreciation_result($state, $appreciation_rate); |
| 173 | $state.s0 = $appr_res.new_s0; |
| 174 | $state.coef = $state.coef * $appr_res.coef_multiplier; |
| 175 | $state.last_ts = timestamp; |
| 176 | }; |
| 177 | |
| 178 | |
| 179 | |
| 180 | |
| 181 | $get_exchange_result_by_state = ($tokens, $delta_r, $trigger_initial_address, $state, $props) => { |
| 182 | require($tokens > 0 AND $delta_r == 0 OR $tokens == 0 AND $delta_r > 0, "invalid input"); |
| 183 | |
| 184 | $r = $state.reserve; |
| 185 | $s = $state.supply; |
| 186 | $p = $get_price_by_state($s, $state); |
| 187 | |
| 188 | |
| 189 | $swap_fee_rate = $props.swap_fee; |
| 190 | $arb_profit_tax_rate = $props.arb_profit_tax; |
| 191 | |
| 192 | $key = $tokens ? 'last_sell' : 'last_buy'; |
| 193 | $last_trade = $state[$key]; |
| 194 | $bMerge = (timestamp <= $last_trade.ts + $trade_merge_period AND $trigger_initial_address == $last_trade.address); |
| 195 | $recent_tax = $bMerge ? $last_trade.tax : 0; |
| 196 | $recent_delta_s = $bMerge ? $last_trade.delta_s : 0; |
| 197 | $initial_p = $bMerge ? ($tokens ? max($p, $last_trade.initial_p) : min($p, $last_trade.initial_p)) : $p; |
| 198 | |
| 199 | if ($tokens) { |
| 200 | $new_s = $s - $tokens; |
| 201 | $net_new_r = $get_reserve_by_state($new_s, $state); |
| 202 | $swap_fee = $swap_fee_rate * ($r - $net_new_r); |
| 203 | $delta_s = -$tokens; |
| 204 | } |
| 205 | else { |
| 206 | $gross_new_r = $r + $delta_r; |
| 207 | $swap_fee = $r ? $swap_fee_rate * $delta_r : 0; |
| 208 | $new_r1 = $r + $delta_r - $swap_fee; |
| 209 | $new_s1 = $get_tokens_by_state($new_r1, $state); |
| 210 | |
| 211 | $new_p1 = $get_price_by_state($new_s1, $state); |
| 212 | |
| 213 | $arb_profit_tax = $r ? $arb_profit_tax_rate * ($new_p1 - $initial_p) * ($new_s1 - $s + $recent_delta_s) / 2 - $recent_tax : 0; |
| 214 | |
| 215 | $net_new_r = $new_r1 - $arb_profit_tax; |
| 216 | require($net_new_r >= $r, "net new r should grow, got "||$net_new_r); |
| 217 | $new_s = $get_tokens_by_state($net_new_r, $state); |
| 218 | |
| 219 | $delta_s = $new_s - $s; |
| 220 | } |
| 221 | |
| 222 | $new_p = $get_price_by_state($new_s, $state); |
| 223 | |
| 224 | |
| 225 | if ($tokens) |
| 226 | $arb_profit_tax = $arb_profit_tax_rate * ($initial_p - $new_p) * ($tokens - $recent_delta_s) / 2 - $recent_tax; |
| 227 | |
| 228 | require($arb_profit_tax >= 0, "arb_profit_tax="||$arb_profit_tax); |
| 229 | $total_fee = $swap_fee + $arb_profit_tax; |
| 230 | |
| 231 | if ($tokens){ |
| 232 | $gross_new_r = ceil($net_new_r + $total_fee); |
| 233 | $payout = $r - $gross_new_r; |
| 234 | require($payout >= 0, "invalid payout "||$payout); |
| 235 | $fee_percent = $total_fee / ($r - $net_new_r) * 100; |
| 236 | } |
| 237 | else{ |
| 238 | require($total_fee < $delta_r, "total fee would exceed the received amount "||$total_fee); |
| 239 | $fee_percent = $total_fee / $delta_r * 100; |
| 240 | } |
| 241 | |
| 242 | $coef_multiplier = $gross_new_r / $net_new_r; |
| 243 | require($coef_multiplier >= 1, "invalid coef multiplier "||$coef_multiplier); |
| 244 | |
| 245 | $state[$key].delta_s = ($bMerge ? $last_trade.delta_s : 0) + $delta_s; |
| 246 | $state[$key].initial_p = $initial_p; |
| 247 | $state[$key].tax = $arb_profit_tax; |
| 248 | $state[$key].ts = timestamp; |
| 249 | $state[$key].address = $trigger_initial_address; |
| 250 | |
| 251 | { |
| 252 | payout: $payout, |
| 253 | delta_s: $delta_s, |
| 254 | old_reserve: $r, |
| 255 | new_reserve: $gross_new_r, |
| 256 | delta_reserve: $gross_new_r - $r, |
| 257 | old_price: $p, |
| 258 | new_price: $new_p, |
| 259 | swap_fee: $swap_fee, |
| 260 | arb_profit_tax: $arb_profit_tax, |
| 261 | total_fee: $total_fee, |
| 262 | fee_percent: $fee_percent, |
| 263 | coef_multiplier: $coef_multiplier, |
| 264 | } |
| 265 | }; |
| 266 | |
| 267 | }", |
| 268 | "messages": [ |
| 269 | { |
| 270 | "app": "state", |
| 271 | "state": "{ |
| 272 | bounce("library only"); |
| 273 | }" |
| 274 | } |
| 275 | ] |
| 276 | } |
| 277 | ] |